diff options
author | Alexandre Belloni <alexandre.belloni@free-electrons.com> | 2018-01-05 19:09:26 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2018-01-09 08:54:59 -0500 |
commit | ce8dc0943357a5d10b05dcf0556b537c1d7b8b1f (patch) | |
tree | a02204f58512c73e3ca06fc3b8f694155a1cd1ad /drivers | |
parent | b67ecdec45b43a0c17a2e66e4d72303dfa3a8a96 (diff) |
pinctrl: Add Microsemi Ocelot SoC driver
The Microsemi Ocelot SoC has a few pins that can be used as GPIOs or take
multiple other functions. Add a driver for the pinmuxing and the GPIOs.
There is currently no support for interrupts.
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pinctrl/Kconfig | 11 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-ocelot.c | 511 |
3 files changed, 523 insertions, 0 deletions
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 1dd445116432..0f254b35c378 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig | |||
@@ -357,6 +357,17 @@ config PINCTRL_RK805 | |||
357 | help | 357 | help |
358 | This selects the pinctrl driver for RK805. | 358 | This selects the pinctrl driver for RK805. |
359 | 359 | ||
360 | config PINCTRL_OCELOT | ||
361 | bool "Pinctrl driver for the Microsemi Ocelot SoCs" | ||
362 | default y | ||
363 | depends on OF | ||
364 | depends on MSCC_OCELOT || COMPILE_TEST | ||
365 | select GPIOLIB | ||
366 | select GENERIC_PINCONF | ||
367 | select GENERIC_PINCTRL_GROUPS | ||
368 | select GENERIC_PINMUX_FUNCTIONS | ||
369 | select REGMAP_MMIO | ||
370 | |||
360 | source "drivers/pinctrl/aspeed/Kconfig" | 371 | source "drivers/pinctrl/aspeed/Kconfig" |
361 | source "drivers/pinctrl/bcm/Kconfig" | 372 | source "drivers/pinctrl/bcm/Kconfig" |
362 | source "drivers/pinctrl/berlin/Kconfig" | 373 | source "drivers/pinctrl/berlin/Kconfig" |
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 2341228eb718..d3692633e9ed 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile | |||
@@ -46,6 +46,7 @@ obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o | |||
46 | obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o | 46 | obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o |
47 | obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o | 47 | obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o |
48 | obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o | 48 | obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o |
49 | obj-$(CONFIG_PINCTRL_OCELOT) += pinctrl-ocelot.o | ||
49 | 50 | ||
50 | obj-$(CONFIG_ARCH_ASPEED) += aspeed/ | 51 | obj-$(CONFIG_ARCH_ASPEED) += aspeed/ |
51 | obj-y += bcm/ | 52 | obj-y += bcm/ |
diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c new file mode 100644 index 000000000000..01a50d969111 --- /dev/null +++ b/drivers/pinctrl/pinctrl-ocelot.c | |||
@@ -0,0 +1,511 @@ | |||
1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) | ||
2 | /* | ||
3 | * Microsemi SoCs pinctrl driver | ||
4 | * | ||
5 | * Author: <alexandre.belloni@free-electrons.com> | ||
6 | * License: Dual MIT/GPL | ||
7 | * Copyright (c) 2017 Microsemi Corporation | ||
8 | */ | ||
9 | |||
10 | #include <linux/gpio/driver.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/of_device.h> | ||
14 | #include <linux/of_platform.h> | ||
15 | #include <linux/pinctrl/pinctrl.h> | ||
16 | #include <linux/pinctrl/pinmux.h> | ||
17 | #include <linux/pinctrl/pinconf.h> | ||
18 | #include <linux/pinctrl/pinconf-generic.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/regmap.h> | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | #include "core.h" | ||
24 | #include "pinconf.h" | ||
25 | #include "pinmux.h" | ||
26 | |||
27 | #define OCELOT_GPIO_OUT_SET 0x0 | ||
28 | #define OCELOT_GPIO_OUT_CLR 0x4 | ||
29 | #define OCELOT_GPIO_OUT 0x8 | ||
30 | #define OCELOT_GPIO_IN 0xc | ||
31 | #define OCELOT_GPIO_OE 0x10 | ||
32 | #define OCELOT_GPIO_INTR 0x14 | ||
33 | #define OCELOT_GPIO_INTR_ENA 0x18 | ||
34 | #define OCELOT_GPIO_INTR_IDENT 0x1c | ||
35 | #define OCELOT_GPIO_ALT0 0x20 | ||
36 | #define OCELOT_GPIO_ALT1 0x24 | ||
37 | #define OCELOT_GPIO_SD_MAP 0x28 | ||
38 | |||
39 | #define OCELOT_PINS 22 | ||
40 | #define OCELOT_FUNC_PER_PIN 4 | ||
41 | |||
42 | enum { | ||
43 | FUNC_NONE, | ||
44 | FUNC_GPIO, | ||
45 | FUNC_IRQ0_IN, | ||
46 | FUNC_IRQ0_OUT, | ||
47 | FUNC_IRQ1_IN, | ||
48 | FUNC_IRQ1_OUT, | ||
49 | FUNC_MIIM1, | ||
50 | FUNC_PCI_WAKE, | ||
51 | FUNC_PTP0, | ||
52 | FUNC_PTP1, | ||
53 | FUNC_PTP2, | ||
54 | FUNC_PTP3, | ||
55 | FUNC_PWM, | ||
56 | FUNC_RECO_CLK0, | ||
57 | FUNC_RECO_CLK1, | ||
58 | FUNC_SFP0, | ||
59 | FUNC_SFP1, | ||
60 | FUNC_SFP2, | ||
61 | FUNC_SFP3, | ||
62 | FUNC_SFP4, | ||
63 | FUNC_SFP5, | ||
64 | FUNC_SG0, | ||
65 | FUNC_SI, | ||
66 | FUNC_TACHO, | ||
67 | FUNC_TWI, | ||
68 | FUNC_TWI_SCL_M, | ||
69 | FUNC_UART, | ||
70 | FUNC_UART2, | ||
71 | FUNC_MAX | ||
72 | }; | ||
73 | |||
74 | static const char *const ocelot_function_names[] = { | ||
75 | [FUNC_NONE] = "none", | ||
76 | [FUNC_GPIO] = "gpio", | ||
77 | [FUNC_IRQ0_IN] = "irq0_in", | ||
78 | [FUNC_IRQ0_OUT] = "irq0_out", | ||
79 | [FUNC_IRQ1_IN] = "irq1_in", | ||
80 | [FUNC_IRQ1_OUT] = "irq1_out", | ||
81 | [FUNC_MIIM1] = "miim1", | ||
82 | [FUNC_PCI_WAKE] = "pci_wake", | ||
83 | [FUNC_PTP0] = "ptp0", | ||
84 | [FUNC_PTP1] = "ptp1", | ||
85 | [FUNC_PTP2] = "ptp2", | ||
86 | [FUNC_PTP3] = "ptp3", | ||
87 | [FUNC_PWM] = "pwm", | ||
88 | [FUNC_RECO_CLK0] = "reco_clk0", | ||
89 | [FUNC_RECO_CLK1] = "reco_clk1", | ||
90 | [FUNC_SFP0] = "sfp0", | ||
91 | [FUNC_SFP1] = "sfp1", | ||
92 | [FUNC_SFP2] = "sfp2", | ||
93 | [FUNC_SFP3] = "sfp3", | ||
94 | [FUNC_SFP4] = "sfp4", | ||
95 | [FUNC_SFP5] = "sfp5", | ||
96 | [FUNC_SG0] = "sg0", | ||
97 | [FUNC_SI] = "si", | ||
98 | [FUNC_TACHO] = "tacho", | ||
99 | [FUNC_TWI] = "twi", | ||
100 | [FUNC_TWI_SCL_M] = "twi_scl_m", | ||
101 | [FUNC_UART] = "uart", | ||
102 | [FUNC_UART2] = "uart2", | ||
103 | }; | ||
104 | |||
105 | struct ocelot_pmx_func { | ||
106 | const char **groups; | ||
107 | unsigned int ngroups; | ||
108 | }; | ||
109 | |||
110 | struct ocelot_pin_caps { | ||
111 | unsigned int pin; | ||
112 | unsigned char functions[OCELOT_FUNC_PER_PIN]; | ||
113 | }; | ||
114 | |||
115 | struct ocelot_pinctrl { | ||
116 | struct device *dev; | ||
117 | struct pinctrl_dev *pctl; | ||
118 | struct gpio_chip gpio_chip; | ||
119 | struct regmap *map; | ||
120 | struct ocelot_pmx_func func[FUNC_MAX]; | ||
121 | }; | ||
122 | |||
123 | #define OCELOT_P(p, f0, f1, f2) \ | ||
124 | static struct ocelot_pin_caps ocelot_pin_##p = { \ | ||
125 | .pin = p, \ | ||
126 | .functions = { \ | ||
127 | FUNC_GPIO, FUNC_##f0, FUNC_##f1, FUNC_##f2, \ | ||
128 | }, \ | ||
129 | } | ||
130 | |||
131 | OCELOT_P(0, SG0, NONE, NONE); | ||
132 | OCELOT_P(1, SG0, NONE, NONE); | ||
133 | OCELOT_P(2, SG0, NONE, NONE); | ||
134 | OCELOT_P(3, SG0, NONE, NONE); | ||
135 | OCELOT_P(4, IRQ0_IN, IRQ0_OUT, TWI); | ||
136 | OCELOT_P(5, IRQ1_IN, IRQ1_OUT, PCI_WAKE); | ||
137 | OCELOT_P(6, UART, TWI_SCL_M, NONE); | ||
138 | OCELOT_P(7, UART, TWI_SCL_M, NONE); | ||
139 | OCELOT_P(8, SI, TWI_SCL_M, IRQ0_OUT); | ||
140 | OCELOT_P(9, SI, TWI_SCL_M, IRQ1_OUT); | ||
141 | OCELOT_P(10, PTP2, TWI_SCL_M, SFP0); | ||
142 | OCELOT_P(11, PTP3, TWI_SCL_M, SFP1); | ||
143 | OCELOT_P(12, UART2, TWI_SCL_M, SFP2); | ||
144 | OCELOT_P(13, UART2, TWI_SCL_M, SFP3); | ||
145 | OCELOT_P(14, MIIM1, TWI_SCL_M, SFP4); | ||
146 | OCELOT_P(15, MIIM1, TWI_SCL_M, SFP5); | ||
147 | OCELOT_P(16, TWI, NONE, SI); | ||
148 | OCELOT_P(17, TWI, TWI_SCL_M, SI); | ||
149 | OCELOT_P(18, PTP0, TWI_SCL_M, NONE); | ||
150 | OCELOT_P(19, PTP1, TWI_SCL_M, NONE); | ||
151 | OCELOT_P(20, RECO_CLK0, TACHO, NONE); | ||
152 | OCELOT_P(21, RECO_CLK1, PWM, NONE); | ||
153 | |||
154 | #define OCELOT_PIN(n) { \ | ||
155 | .number = n, \ | ||
156 | .name = "GPIO_"#n, \ | ||
157 | .drv_data = &ocelot_pin_##n \ | ||
158 | } | ||
159 | |||
160 | static const struct pinctrl_pin_desc ocelot_pins[] = { | ||
161 | OCELOT_PIN(0), | ||
162 | OCELOT_PIN(1), | ||
163 | OCELOT_PIN(2), | ||
164 | OCELOT_PIN(3), | ||
165 | OCELOT_PIN(4), | ||
166 | OCELOT_PIN(5), | ||
167 | OCELOT_PIN(6), | ||
168 | OCELOT_PIN(7), | ||
169 | OCELOT_PIN(8), | ||
170 | OCELOT_PIN(9), | ||
171 | OCELOT_PIN(10), | ||
172 | OCELOT_PIN(11), | ||
173 | OCELOT_PIN(12), | ||
174 | OCELOT_PIN(13), | ||
175 | OCELOT_PIN(14), | ||
176 | OCELOT_PIN(15), | ||
177 | OCELOT_PIN(16), | ||
178 | OCELOT_PIN(17), | ||
179 | OCELOT_PIN(18), | ||
180 | OCELOT_PIN(19), | ||
181 | OCELOT_PIN(20), | ||
182 | OCELOT_PIN(21), | ||
183 | }; | ||
184 | |||
185 | static int ocelot_get_functions_count(struct pinctrl_dev *pctldev) | ||
186 | { | ||
187 | return ARRAY_SIZE(ocelot_function_names); | ||
188 | } | ||
189 | |||
190 | static const char *ocelot_get_function_name(struct pinctrl_dev *pctldev, | ||
191 | unsigned int function) | ||
192 | { | ||
193 | return ocelot_function_names[function]; | ||
194 | } | ||
195 | |||
196 | static int ocelot_get_function_groups(struct pinctrl_dev *pctldev, | ||
197 | unsigned int function, | ||
198 | const char *const **groups, | ||
199 | unsigned *const num_groups) | ||
200 | { | ||
201 | struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); | ||
202 | |||
203 | *groups = info->func[function].groups; | ||
204 | *num_groups = info->func[function].ngroups; | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static int ocelot_pin_function_idx(unsigned int pin, unsigned int function) | ||
210 | { | ||
211 | struct ocelot_pin_caps *p = ocelot_pins[pin].drv_data; | ||
212 | int i; | ||
213 | |||
214 | for (i = 0; i < OCELOT_FUNC_PER_PIN; i++) { | ||
215 | if (function == p->functions[i]) | ||
216 | return i; | ||
217 | } | ||
218 | |||
219 | return -1; | ||
220 | } | ||
221 | |||
222 | static int ocelot_pinmux_set_mux(struct pinctrl_dev *pctldev, | ||
223 | unsigned int selector, unsigned int group) | ||
224 | { | ||
225 | struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); | ||
226 | struct ocelot_pin_caps *pin = ocelot_pins[group].drv_data; | ||
227 | int f; | ||
228 | |||
229 | f = ocelot_pin_function_idx(group, selector); | ||
230 | if (f < 0) | ||
231 | return -EINVAL; | ||
232 | |||
233 | /* | ||
234 | * f is encoded on two bits. | ||
235 | * bit 0 of f goes in BIT(pin) of ALT0, bit 1 of f goes in BIT(pin) of | ||
236 | * ALT1 | ||
237 | * This is racy because both registers can't be updated at the same time | ||
238 | * but it doesn't matter much for now. | ||
239 | */ | ||
240 | regmap_update_bits(info->map, OCELOT_GPIO_ALT0, BIT(pin->pin), | ||
241 | f << pin->pin); | ||
242 | regmap_update_bits(info->map, OCELOT_GPIO_ALT1, BIT(pin->pin), | ||
243 | f << (pin->pin - 1)); | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int ocelot_gpio_set_direction(struct pinctrl_dev *pctldev, | ||
249 | struct pinctrl_gpio_range *range, | ||
250 | unsigned int pin, bool input) | ||
251 | { | ||
252 | struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); | ||
253 | |||
254 | regmap_update_bits(info->map, OCELOT_GPIO_OE, BIT(pin), | ||
255 | input ? BIT(pin) : 0); | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static int ocelot_gpio_request_enable(struct pinctrl_dev *pctldev, | ||
261 | struct pinctrl_gpio_range *range, | ||
262 | unsigned int offset) | ||
263 | { | ||
264 | struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); | ||
265 | |||
266 | regmap_update_bits(info->map, OCELOT_GPIO_ALT0, BIT(offset), 0); | ||
267 | regmap_update_bits(info->map, OCELOT_GPIO_ALT1, BIT(offset), 0); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static const struct pinmux_ops ocelot_pmx_ops = { | ||
273 | .get_functions_count = ocelot_get_functions_count, | ||
274 | .get_function_name = ocelot_get_function_name, | ||
275 | .get_function_groups = ocelot_get_function_groups, | ||
276 | .set_mux = ocelot_pinmux_set_mux, | ||
277 | .gpio_set_direction = ocelot_gpio_set_direction, | ||
278 | .gpio_request_enable = ocelot_gpio_request_enable, | ||
279 | }; | ||
280 | |||
281 | static int ocelot_pctl_get_groups_count(struct pinctrl_dev *pctldev) | ||
282 | { | ||
283 | return ARRAY_SIZE(ocelot_pins); | ||
284 | } | ||
285 | |||
286 | static const char *ocelot_pctl_get_group_name(struct pinctrl_dev *pctldev, | ||
287 | unsigned int group) | ||
288 | { | ||
289 | return ocelot_pins[group].name; | ||
290 | } | ||
291 | |||
292 | static int ocelot_pctl_get_group_pins(struct pinctrl_dev *pctldev, | ||
293 | unsigned int group, | ||
294 | const unsigned int **pins, | ||
295 | unsigned int *num_pins) | ||
296 | { | ||
297 | *pins = &ocelot_pins[group].number; | ||
298 | *num_pins = 1; | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static const struct pinctrl_ops ocelot_pctl_ops = { | ||
304 | .get_groups_count = ocelot_pctl_get_groups_count, | ||
305 | .get_group_name = ocelot_pctl_get_group_name, | ||
306 | .get_group_pins = ocelot_pctl_get_group_pins, | ||
307 | .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, | ||
308 | .dt_free_map = pinconf_generic_dt_free_map, | ||
309 | }; | ||
310 | |||
311 | static struct pinctrl_desc ocelot_desc = { | ||
312 | .name = "ocelot-pinctrl", | ||
313 | .pins = ocelot_pins, | ||
314 | .npins = ARRAY_SIZE(ocelot_pins), | ||
315 | .pctlops = &ocelot_pctl_ops, | ||
316 | .pmxops = &ocelot_pmx_ops, | ||
317 | .owner = THIS_MODULE, | ||
318 | }; | ||
319 | |||
320 | static int ocelot_create_group_func_map(struct device *dev, | ||
321 | struct ocelot_pinctrl *info) | ||
322 | { | ||
323 | u16 pins[ARRAY_SIZE(ocelot_pins)]; | ||
324 | int f, npins, i; | ||
325 | |||
326 | for (f = 0; f < FUNC_MAX; f++) { | ||
327 | for (npins = 0, i = 0; i < ARRAY_SIZE(ocelot_pins); i++) { | ||
328 | if (ocelot_pin_function_idx(i, f) >= 0) | ||
329 | pins[npins++] = i; | ||
330 | } | ||
331 | |||
332 | info->func[f].ngroups = npins; | ||
333 | info->func[f].groups = devm_kzalloc(dev, npins * | ||
334 | sizeof(char *), | ||
335 | GFP_KERNEL); | ||
336 | if (!info->func[f].groups) | ||
337 | return -ENOMEM; | ||
338 | |||
339 | for (i = 0; i < npins; i++) | ||
340 | info->func[f].groups[i] = ocelot_pins[pins[i]].name; | ||
341 | } | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static int ocelot_pinctrl_register(struct platform_device *pdev, | ||
347 | struct ocelot_pinctrl *info) | ||
348 | { | ||
349 | int ret; | ||
350 | |||
351 | ret = ocelot_create_group_func_map(&pdev->dev, info); | ||
352 | if (ret) { | ||
353 | dev_err(&pdev->dev, "Unable to create group func map.\n"); | ||
354 | return ret; | ||
355 | } | ||
356 | |||
357 | info->pctl = devm_pinctrl_register(&pdev->dev, &ocelot_desc, info); | ||
358 | if (IS_ERR(info->pctl)) { | ||
359 | dev_err(&pdev->dev, "Failed to register pinctrl\n"); | ||
360 | return PTR_ERR(info->pctl); | ||
361 | } | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int ocelot_gpio_get(struct gpio_chip *chip, unsigned int offset) | ||
367 | { | ||
368 | struct ocelot_pinctrl *info = gpiochip_get_data(chip); | ||
369 | unsigned int val; | ||
370 | |||
371 | regmap_read(info->map, OCELOT_GPIO_IN, &val); | ||
372 | |||
373 | return !!(val & BIT(offset)); | ||
374 | } | ||
375 | |||
376 | static void ocelot_gpio_set(struct gpio_chip *chip, unsigned int offset, | ||
377 | int value) | ||
378 | { | ||
379 | struct ocelot_pinctrl *info = gpiochip_get_data(chip); | ||
380 | |||
381 | if (value) | ||
382 | regmap_write(info->map, OCELOT_GPIO_OUT_SET, BIT(offset)); | ||
383 | else | ||
384 | regmap_write(info->map, OCELOT_GPIO_OUT_CLR, BIT(offset)); | ||
385 | } | ||
386 | |||
387 | static int ocelot_gpio_get_direction(struct gpio_chip *chip, | ||
388 | unsigned int offset) | ||
389 | { | ||
390 | struct ocelot_pinctrl *info = gpiochip_get_data(chip); | ||
391 | unsigned int val; | ||
392 | |||
393 | regmap_read(info->map, OCELOT_GPIO_OE, &val); | ||
394 | |||
395 | return !(val & BIT(offset)); | ||
396 | } | ||
397 | |||
398 | static int ocelot_gpio_direction_input(struct gpio_chip *chip, | ||
399 | unsigned int offset) | ||
400 | { | ||
401 | return pinctrl_gpio_direction_input(chip->base + offset); | ||
402 | } | ||
403 | |||
404 | static int ocelot_gpio_direction_output(struct gpio_chip *chip, | ||
405 | unsigned int offset, int value) | ||
406 | { | ||
407 | struct ocelot_pinctrl *info = gpiochip_get_data(chip); | ||
408 | unsigned int pin = BIT(offset); | ||
409 | |||
410 | if (value) | ||
411 | regmap_write(info->map, OCELOT_GPIO_OUT_SET, pin); | ||
412 | else | ||
413 | regmap_write(info->map, OCELOT_GPIO_OUT_CLR, pin); | ||
414 | |||
415 | return pinctrl_gpio_direction_output(chip->base + offset); | ||
416 | } | ||
417 | |||
418 | static const struct gpio_chip ocelot_gpiolib_chip = { | ||
419 | .request = gpiochip_generic_request, | ||
420 | .free = gpiochip_generic_free, | ||
421 | .set = ocelot_gpio_set, | ||
422 | .get = ocelot_gpio_get, | ||
423 | .get_direction = ocelot_gpio_get_direction, | ||
424 | .direction_input = ocelot_gpio_direction_input, | ||
425 | .direction_output = ocelot_gpio_direction_output, | ||
426 | .owner = THIS_MODULE, | ||
427 | }; | ||
428 | |||
429 | static int ocelot_gpiochip_register(struct platform_device *pdev, | ||
430 | struct ocelot_pinctrl *info) | ||
431 | { | ||
432 | struct gpio_chip *gc; | ||
433 | int ret; | ||
434 | |||
435 | info->gpio_chip = ocelot_gpiolib_chip; | ||
436 | |||
437 | gc = &info->gpio_chip; | ||
438 | gc->ngpio = OCELOT_PINS; | ||
439 | gc->parent = &pdev->dev; | ||
440 | gc->base = 0; | ||
441 | gc->of_node = info->dev->of_node; | ||
442 | gc->label = "ocelot-gpio"; | ||
443 | |||
444 | ret = devm_gpiochip_add_data(&pdev->dev, gc, info); | ||
445 | if (ret) | ||
446 | return ret; | ||
447 | |||
448 | /* TODO: this can be used as an irqchip but no board is using that */ | ||
449 | |||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | static const struct regmap_config ocelot_pinctrl_regmap_config = { | ||
454 | .reg_bits = 32, | ||
455 | .val_bits = 32, | ||
456 | .reg_stride = 4, | ||
457 | .max_register = 0x64, | ||
458 | }; | ||
459 | |||
460 | static const struct of_device_id ocelot_pinctrl_of_match[] = { | ||
461 | { .compatible = "mscc,ocelot-pinctrl" }, | ||
462 | {}, | ||
463 | }; | ||
464 | |||
465 | int ocelot_pinctrl_probe(struct platform_device *pdev) | ||
466 | { | ||
467 | struct device *dev = &pdev->dev; | ||
468 | struct ocelot_pinctrl *info; | ||
469 | void __iomem *base; | ||
470 | int ret; | ||
471 | |||
472 | info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); | ||
473 | if (!info) | ||
474 | return -ENOMEM; | ||
475 | |||
476 | base = devm_ioremap_resource(dev, | ||
477 | platform_get_resource(pdev, IORESOURCE_MEM, 0)); | ||
478 | if (IS_ERR(base)) { | ||
479 | dev_err(dev, "Failed to ioremap registers\n"); | ||
480 | return PTR_ERR(base); | ||
481 | } | ||
482 | |||
483 | info->map = devm_regmap_init_mmio(dev, base, | ||
484 | &ocelot_pinctrl_regmap_config); | ||
485 | if (IS_ERR(info->map)) { | ||
486 | dev_err(dev, "Failed to create regmap\n"); | ||
487 | return PTR_ERR(info->map); | ||
488 | } | ||
489 | dev_set_drvdata(dev, info->map); | ||
490 | info->dev = dev; | ||
491 | |||
492 | ret = ocelot_pinctrl_register(pdev, info); | ||
493 | if (ret) | ||
494 | return ret; | ||
495 | |||
496 | ret = ocelot_gpiochip_register(pdev, info); | ||
497 | if (ret) | ||
498 | return ret; | ||
499 | |||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | static struct platform_driver ocelot_pinctrl_driver = { | ||
504 | .driver = { | ||
505 | .name = "pinctrl-ocelot", | ||
506 | .of_match_table = of_match_ptr(ocelot_pinctrl_of_match), | ||
507 | .suppress_bind_attrs = true, | ||
508 | }, | ||
509 | .probe = ocelot_pinctrl_probe, | ||
510 | }; | ||
511 | builtin_platform_driver(ocelot_pinctrl_driver); | ||