]> Git Repo - J-linux.git/blob - drivers/pinctrl/intel/pinctrl-intel-platform.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / pinctrl / intel / pinctrl-intel-platform.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Intel PCH pinctrl/GPIO driver
4  *
5  * Copyright (C) 2021-2023, Intel Corporation
6  * Author: Andy Shevchenko <[email protected]>
7  */
8
9 #include <linux/mod_devicetable.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/pm.h>
13 #include <linux/property.h>
14 #include <linux/string_helpers.h>
15
16 #include <linux/pinctrl/pinctrl.h>
17
18 #include "pinctrl-intel.h"
19
20 struct intel_platform_pins {
21         struct pinctrl_pin_desc *pins;
22         size_t npins;
23 };
24
25 static int intel_platform_pinctrl_prepare_pins(struct device *dev, size_t base,
26                                                const char *name, u32 size,
27                                                struct intel_platform_pins *pins)
28 {
29         struct pinctrl_pin_desc *descs;
30         char **pin_names;
31         unsigned int i;
32
33         pin_names = devm_kasprintf_strarray(dev, name, size);
34         if (IS_ERR(pin_names))
35                 return PTR_ERR(pin_names);
36
37         descs = devm_krealloc_array(dev, pins->pins, base + size, sizeof(*descs), GFP_KERNEL);
38         if (!descs)
39                 return -ENOMEM;
40
41         for (i = 0; i < size; i++) {
42                 unsigned int pin_number = base + i;
43                 char *pin_name = pin_names[i];
44                 struct pinctrl_pin_desc *desc;
45
46                 /* Unify delimiter for pin name */
47                 strreplace(pin_name, '-', '_');
48
49                 desc = &descs[pin_number];
50                 desc->number = pin_number;
51                 desc->name = pin_name;
52         }
53
54         pins->pins = descs;
55         pins->npins = base + size;
56
57         return 0;
58 }
59
60 static int intel_platform_pinctrl_prepare_group(struct device *dev,
61                                                 struct fwnode_handle *child,
62                                                 struct intel_padgroup *gpp,
63                                                 struct intel_platform_pins *pins)
64 {
65         size_t base = pins->npins;
66         const char *name;
67         u32 size;
68         int ret;
69
70         ret = fwnode_property_read_string(child, "intc-gpio-group-name", &name);
71         if (ret)
72                 return ret;
73
74         ret = fwnode_property_read_u32(child, "intc-gpio-pad-count", &size);
75         if (ret)
76                 return ret;
77
78         ret = intel_platform_pinctrl_prepare_pins(dev, base, name, size, pins);
79         if (ret)
80                 return ret;
81
82         gpp->base = base;
83         gpp->size = size;
84         gpp->gpio_base = INTEL_GPIO_BASE_MATCH;
85
86         return 0;
87 }
88
89 static int intel_platform_pinctrl_prepare_community(struct device *dev,
90                                                     struct intel_community *community,
91                                                     struct intel_platform_pins *pins)
92 {
93         struct intel_padgroup *gpps;
94         unsigned int group;
95         size_t ngpps;
96         u32 offset;
97         int ret;
98
99         ret = device_property_read_u32(dev, "intc-gpio-pad-ownership-offset", &offset);
100         if (ret)
101                 return ret;
102         community->padown_offset = offset;
103
104         ret = device_property_read_u32(dev, "intc-gpio-pad-configuration-lock-offset", &offset);
105         if (ret)
106                 return ret;
107         community->padcfglock_offset = offset;
108
109         ret = device_property_read_u32(dev, "intc-gpio-host-software-pad-ownership-offset", &offset);
110         if (ret)
111                 return ret;
112         community->hostown_offset = offset;
113
114         ret = device_property_read_u32(dev, "intc-gpio-gpi-interrupt-status-offset", &offset);
115         if (ret)
116                 return ret;
117         community->is_offset = offset;
118
119         ret = device_property_read_u32(dev, "intc-gpio-gpi-interrupt-enable-offset", &offset);
120         if (ret)
121                 return ret;
122         community->ie_offset = offset;
123
124         ngpps = device_get_child_node_count(dev);
125         if (!ngpps)
126                 return -ENODEV;
127
128         gpps = devm_kcalloc(dev, ngpps, sizeof(*gpps), GFP_KERNEL);
129         if (!gpps)
130                 return -ENOMEM;
131
132         group = 0;
133         device_for_each_child_node_scoped(dev, child) {
134                 struct intel_padgroup *gpp = &gpps[group];
135
136                 gpp->reg_num = group;
137
138                 ret = intel_platform_pinctrl_prepare_group(dev, child, gpp, pins);
139                 if (ret)
140                         return ret;
141
142                 group++;
143         }
144
145         community->ngpps = ngpps;
146         community->gpps = gpps;
147
148         return 0;
149 }
150
151 static int intel_platform_pinctrl_prepare_soc_data(struct device *dev,
152                                                    struct intel_pinctrl_soc_data *data)
153 {
154         struct intel_platform_pins pins = {};
155         struct intel_community *communities;
156         size_t ncommunities;
157         unsigned int i;
158         int ret;
159
160         /* Version 1.0 of the specification assumes only a single community per device node */
161         ncommunities = 1;
162         communities = devm_kcalloc(dev, ncommunities, sizeof(*communities), GFP_KERNEL);
163         if (!communities)
164                 return -ENOMEM;
165
166         for (i = 0; i < ncommunities; i++) {
167                 struct intel_community *community = &communities[i];
168
169                 community->barno = i;
170                 community->pin_base = pins.npins;
171
172                 ret = intel_platform_pinctrl_prepare_community(dev, community, &pins);
173                 if (ret)
174                         return ret;
175
176                 community->npins = pins.npins - community->pin_base;
177         }
178
179         data->ncommunities = ncommunities;
180         data->communities = communities;
181
182         data->npins = pins.npins;
183         data->pins = pins.pins;
184
185         return 0;
186 }
187
188 static int intel_platform_pinctrl_probe(struct platform_device *pdev)
189 {
190         struct intel_pinctrl_soc_data *data;
191         struct device *dev = &pdev->dev;
192         int ret;
193
194         data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
195         if (!data)
196                 return -ENOMEM;
197
198         ret = intel_platform_pinctrl_prepare_soc_data(dev, data);
199         if (ret)
200                 return ret;
201
202         return intel_pinctrl_probe(pdev, data);
203 }
204
205 static const struct acpi_device_id intel_platform_pinctrl_acpi_match[] = {
206         { "INTC105F" },
207         { }
208 };
209 MODULE_DEVICE_TABLE(acpi, intel_platform_pinctrl_acpi_match);
210
211 static struct platform_driver intel_platform_pinctrl_driver = {
212         .probe = intel_platform_pinctrl_probe,
213         .driver = {
214                 .name = "intel-pinctrl",
215                 .acpi_match_table = intel_platform_pinctrl_acpi_match,
216                 .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
217         },
218 };
219 module_platform_driver(intel_platform_pinctrl_driver);
220
221 MODULE_AUTHOR("Andy Shevchenko <[email protected]>");
222 MODULE_DESCRIPTION("Intel PCH pinctrl/GPIO driver");
223 MODULE_LICENSE("GPL v2");
224 MODULE_IMPORT_NS("PINCTRL_INTEL");
This page took 0.039973 seconds and 4 git commands to generate.