1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Driver for BCM6358 GPIO unit (pinctrl + GPIO) |
4 | * |
5 | * Copyright (C) 2021 Álvaro Fernández Rojas <noltari@gmail.com> |
6 | * Copyright (C) 2016 Jonas Gorski <jonas.gorski@gmail.com> |
7 | */ |
8 | |
9 | #include <linux/bits.h> |
10 | #include <linux/gpio/driver.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/of.h> |
13 | #include <linux/pinctrl/pinmux.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/regmap.h> |
16 | |
17 | #include "../pinctrl-utils.h" |
18 | |
19 | #include "pinctrl-bcm63xx.h" |
20 | |
21 | #define BCM6358_NUM_GPIOS 40 |
22 | |
23 | #define BCM6358_MODE_REG 0x18 |
24 | #define BCM6358_MODE_MUX_NONE 0 |
25 | #define BCM6358_MODE_MUX_EBI_CS BIT(5) |
26 | #define BCM6358_MODE_MUX_UART1 BIT(6) |
27 | #define BCM6358_MODE_MUX_SPI_CS BIT(7) |
28 | #define BCM6358_MODE_MUX_ASYNC_MODEM BIT(8) |
29 | #define BCM6358_MODE_MUX_LEGACY_LED BIT(9) |
30 | #define BCM6358_MODE_MUX_SERIAL_LED BIT(10) |
31 | #define BCM6358_MODE_MUX_LED BIT(11) |
32 | #define BCM6358_MODE_MUX_UTOPIA BIT(12) |
33 | #define BCM6358_MODE_MUX_CLKRST BIT(13) |
34 | #define BCM6358_MODE_MUX_PWM_SYN_CLK BIT(14) |
35 | #define BCM6358_MODE_MUX_SYS_IRQ BIT(15) |
36 | |
37 | struct bcm6358_pingroup { |
38 | struct pingroup grp; |
39 | |
40 | const uint16_t mode_val; |
41 | |
42 | /* non-GPIO function muxes require the gpio direction to be set */ |
43 | const uint16_t direction; |
44 | }; |
45 | |
46 | struct bcm6358_function { |
47 | const char *name; |
48 | const char * const *groups; |
49 | const unsigned num_groups; |
50 | }; |
51 | |
52 | struct bcm6358_priv { |
53 | struct regmap_field *overlays; |
54 | }; |
55 | |
56 | #define BCM6358_GPIO_PIN(a, b, bit1, bit2, bit3) \ |
57 | { \ |
58 | .number = a, \ |
59 | .name = b, \ |
60 | .drv_data = (void *)(BCM6358_MODE_MUX_##bit1 | \ |
61 | BCM6358_MODE_MUX_##bit2 | \ |
62 | BCM6358_MODE_MUX_##bit3), \ |
63 | } |
64 | |
65 | static const struct pinctrl_pin_desc bcm6358_pins[] = { |
66 | BCM6358_GPIO_PIN(0, "gpio0" , LED, NONE, NONE), |
67 | BCM6358_GPIO_PIN(1, "gpio1" , LED, NONE, NONE), |
68 | BCM6358_GPIO_PIN(2, "gpio2" , LED, NONE, NONE), |
69 | BCM6358_GPIO_PIN(3, "gpio3" , LED, NONE, NONE), |
70 | PINCTRL_PIN(4, "gpio4" ), |
71 | BCM6358_GPIO_PIN(5, "gpio5" , SYS_IRQ, NONE, NONE), |
72 | BCM6358_GPIO_PIN(6, "gpio6" , SERIAL_LED, NONE, NONE), |
73 | BCM6358_GPIO_PIN(7, "gpio7" , SERIAL_LED, NONE, NONE), |
74 | BCM6358_GPIO_PIN(8, "gpio8" , PWM_SYN_CLK, NONE, NONE), |
75 | BCM6358_GPIO_PIN(9, "gpio09" , LEGACY_LED, NONE, NONE), |
76 | BCM6358_GPIO_PIN(10, "gpio10" , LEGACY_LED, NONE, NONE), |
77 | BCM6358_GPIO_PIN(11, "gpio11" , LEGACY_LED, NONE, NONE), |
78 | BCM6358_GPIO_PIN(12, "gpio12" , LEGACY_LED, ASYNC_MODEM, UTOPIA), |
79 | BCM6358_GPIO_PIN(13, "gpio13" , LEGACY_LED, ASYNC_MODEM, UTOPIA), |
80 | BCM6358_GPIO_PIN(14, "gpio14" , LEGACY_LED, ASYNC_MODEM, UTOPIA), |
81 | BCM6358_GPIO_PIN(15, "gpio15" , LEGACY_LED, ASYNC_MODEM, UTOPIA), |
82 | PINCTRL_PIN(16, "gpio16" ), |
83 | PINCTRL_PIN(17, "gpio17" ), |
84 | PINCTRL_PIN(18, "gpio18" ), |
85 | PINCTRL_PIN(19, "gpio19" ), |
86 | PINCTRL_PIN(20, "gpio20" ), |
87 | PINCTRL_PIN(21, "gpio21" ), |
88 | BCM6358_GPIO_PIN(22, "gpio22" , UTOPIA, NONE, NONE), |
89 | BCM6358_GPIO_PIN(23, "gpio23" , UTOPIA, NONE, NONE), |
90 | BCM6358_GPIO_PIN(24, "gpio24" , UTOPIA, NONE, NONE), |
91 | BCM6358_GPIO_PIN(25, "gpio25" , UTOPIA, NONE, NONE), |
92 | BCM6358_GPIO_PIN(26, "gpio26" , UTOPIA, NONE, NONE), |
93 | BCM6358_GPIO_PIN(27, "gpio27" , UTOPIA, NONE, NONE), |
94 | BCM6358_GPIO_PIN(28, "gpio28" , UTOPIA, UART1, NONE), |
95 | BCM6358_GPIO_PIN(29, "gpio29" , UTOPIA, UART1, NONE), |
96 | BCM6358_GPIO_PIN(30, "gpio30" , UTOPIA, UART1, EBI_CS), |
97 | BCM6358_GPIO_PIN(31, "gpio31" , UTOPIA, UART1, EBI_CS), |
98 | BCM6358_GPIO_PIN(32, "gpio32" , SPI_CS, NONE, NONE), |
99 | BCM6358_GPIO_PIN(33, "gpio33" , SPI_CS, NONE, NONE), |
100 | PINCTRL_PIN(34, "gpio34" ), |
101 | PINCTRL_PIN(35, "gpio35" ), |
102 | PINCTRL_PIN(36, "gpio36" ), |
103 | PINCTRL_PIN(37, "gpio37" ), |
104 | PINCTRL_PIN(38, "gpio38" ), |
105 | PINCTRL_PIN(39, "gpio39" ), |
106 | }; |
107 | |
108 | static unsigned ebi_cs_grp_pins[] = { 30, 31 }; |
109 | |
110 | static unsigned uart1_grp_pins[] = { 28, 29, 30, 31 }; |
111 | |
112 | static unsigned spi_cs_grp_pins[] = { 32, 33 }; |
113 | |
114 | static unsigned async_modem_grp_pins[] = { 12, 13, 14, 15 }; |
115 | |
116 | static unsigned serial_led_grp_pins[] = { 6, 7 }; |
117 | |
118 | static unsigned legacy_led_grp_pins[] = { 9, 10, 11, 12, 13, 14, 15 }; |
119 | |
120 | static unsigned led_grp_pins[] = { 0, 1, 2, 3 }; |
121 | |
122 | static unsigned utopia_grp_pins[] = { |
123 | 12, 13, 14, 15, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, |
124 | }; |
125 | |
126 | static unsigned pwm_syn_clk_grp_pins[] = { 8 }; |
127 | |
128 | static unsigned sys_irq_grp_pins[] = { 5 }; |
129 | |
130 | #define BCM6358_GPIO_MUX_GROUP(n, bit, dir) \ |
131 | { \ |
132 | .grp = BCM_PIN_GROUP(n), \ |
133 | .mode_val = BCM6358_MODE_MUX_##bit, \ |
134 | .direction = dir, \ |
135 | } |
136 | |
137 | static const struct bcm6358_pingroup bcm6358_groups[] = { |
138 | BCM6358_GPIO_MUX_GROUP(ebi_cs_grp, EBI_CS, 0x3), |
139 | BCM6358_GPIO_MUX_GROUP(uart1_grp, UART1, 0x2), |
140 | BCM6358_GPIO_MUX_GROUP(spi_cs_grp, SPI_CS, 0x6), |
141 | BCM6358_GPIO_MUX_GROUP(async_modem_grp, ASYNC_MODEM, 0x6), |
142 | BCM6358_GPIO_MUX_GROUP(legacy_led_grp, LEGACY_LED, 0x7f), |
143 | BCM6358_GPIO_MUX_GROUP(serial_led_grp, SERIAL_LED, 0x3), |
144 | BCM6358_GPIO_MUX_GROUP(led_grp, LED, 0xf), |
145 | BCM6358_GPIO_MUX_GROUP(utopia_grp, UTOPIA, 0x000f), |
146 | BCM6358_GPIO_MUX_GROUP(pwm_syn_clk_grp, PWM_SYN_CLK, 0x1), |
147 | BCM6358_GPIO_MUX_GROUP(sys_irq_grp, SYS_IRQ, 0x1), |
148 | }; |
149 | |
150 | static const char * const ebi_cs_groups[] = { |
151 | "ebi_cs_grp" |
152 | }; |
153 | |
154 | static const char * const uart1_groups[] = { |
155 | "uart1_grp" |
156 | }; |
157 | |
158 | static const char * const spi_cs_2_3_groups[] = { |
159 | "spi_cs_2_3_grp" |
160 | }; |
161 | |
162 | static const char * const async_modem_groups[] = { |
163 | "async_modem_grp" |
164 | }; |
165 | |
166 | static const char * const legacy_led_groups[] = { |
167 | "legacy_led_grp" , |
168 | }; |
169 | |
170 | static const char * const serial_led_groups[] = { |
171 | "serial_led_grp" , |
172 | }; |
173 | |
174 | static const char * const led_groups[] = { |
175 | "led_grp" , |
176 | }; |
177 | |
178 | static const char * const clkrst_groups[] = { |
179 | "clkrst_grp" , |
180 | }; |
181 | |
182 | static const char * const pwm_syn_clk_groups[] = { |
183 | "pwm_syn_clk_grp" , |
184 | }; |
185 | |
186 | static const char * const sys_irq_groups[] = { |
187 | "sys_irq_grp" , |
188 | }; |
189 | |
190 | #define BCM6358_FUN(n) \ |
191 | { \ |
192 | .name = #n, \ |
193 | .groups = n##_groups, \ |
194 | .num_groups = ARRAY_SIZE(n##_groups), \ |
195 | } |
196 | |
197 | static const struct bcm6358_function bcm6358_funcs[] = { |
198 | BCM6358_FUN(ebi_cs), |
199 | BCM6358_FUN(uart1), |
200 | BCM6358_FUN(spi_cs_2_3), |
201 | BCM6358_FUN(async_modem), |
202 | BCM6358_FUN(legacy_led), |
203 | BCM6358_FUN(serial_led), |
204 | BCM6358_FUN(led), |
205 | BCM6358_FUN(clkrst), |
206 | BCM6358_FUN(pwm_syn_clk), |
207 | BCM6358_FUN(sys_irq), |
208 | }; |
209 | |
210 | static int bcm6358_pinctrl_get_group_count(struct pinctrl_dev *pctldev) |
211 | { |
212 | return ARRAY_SIZE(bcm6358_groups); |
213 | } |
214 | |
215 | static const char *bcm6358_pinctrl_get_group_name(struct pinctrl_dev *pctldev, |
216 | unsigned group) |
217 | { |
218 | return bcm6358_groups[group].grp.name; |
219 | } |
220 | |
221 | static int bcm6358_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, |
222 | unsigned group, const unsigned **pins, |
223 | unsigned *npins) |
224 | { |
225 | *pins = bcm6358_groups[group].grp.pins; |
226 | *npins = bcm6358_groups[group].grp.npins; |
227 | |
228 | return 0; |
229 | } |
230 | |
231 | static int bcm6358_pinctrl_get_func_count(struct pinctrl_dev *pctldev) |
232 | { |
233 | return ARRAY_SIZE(bcm6358_funcs); |
234 | } |
235 | |
236 | static const char *bcm6358_pinctrl_get_func_name(struct pinctrl_dev *pctldev, |
237 | unsigned selector) |
238 | { |
239 | return bcm6358_funcs[selector].name; |
240 | } |
241 | |
242 | static int bcm6358_pinctrl_get_groups(struct pinctrl_dev *pctldev, |
243 | unsigned selector, |
244 | const char * const **groups, |
245 | unsigned * const num_groups) |
246 | { |
247 | *groups = bcm6358_funcs[selector].groups; |
248 | *num_groups = bcm6358_funcs[selector].num_groups; |
249 | |
250 | return 0; |
251 | } |
252 | |
253 | static int bcm6358_pinctrl_set_mux(struct pinctrl_dev *pctldev, |
254 | unsigned selector, unsigned group) |
255 | { |
256 | struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); |
257 | struct bcm6358_priv *priv = pc->driver_data; |
258 | const struct bcm6358_pingroup *pg = &bcm6358_groups[group]; |
259 | unsigned int val = pg->mode_val; |
260 | unsigned int mask = val; |
261 | unsigned pin; |
262 | |
263 | for (pin = 0; pin < pg->grp.npins; pin++) |
264 | mask |= (unsigned long)bcm6358_pins[pin].drv_data; |
265 | |
266 | regmap_field_update_bits(field: priv->overlays, mask, val); |
267 | |
268 | for (pin = 0; pin < pg->grp.npins; pin++) { |
269 | struct pinctrl_gpio_range *range; |
270 | unsigned int hw_gpio = bcm6358_pins[pin].number; |
271 | |
272 | range = pinctrl_find_gpio_range_from_pin(pctldev, pin: hw_gpio); |
273 | if (range) { |
274 | struct gpio_chip *gc = range->gc; |
275 | |
276 | if (pg->direction & BIT(pin)) |
277 | gc->direction_output(gc, hw_gpio, 0); |
278 | else |
279 | gc->direction_input(gc, hw_gpio); |
280 | } |
281 | } |
282 | |
283 | return 0; |
284 | } |
285 | |
286 | static int bcm6358_gpio_request_enable(struct pinctrl_dev *pctldev, |
287 | struct pinctrl_gpio_range *range, |
288 | unsigned offset) |
289 | { |
290 | struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); |
291 | struct bcm6358_priv *priv = pc->driver_data; |
292 | unsigned int mask; |
293 | |
294 | mask = (unsigned long) bcm6358_pins[offset].drv_data; |
295 | if (!mask) |
296 | return 0; |
297 | |
298 | /* disable all functions using this pin */ |
299 | return regmap_field_update_bits(field: priv->overlays, mask, val: 0); |
300 | } |
301 | |
302 | static const struct pinctrl_ops bcm6358_pctl_ops = { |
303 | .dt_free_map = pinctrl_utils_free_map, |
304 | .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, |
305 | .get_group_name = bcm6358_pinctrl_get_group_name, |
306 | .get_group_pins = bcm6358_pinctrl_get_group_pins, |
307 | .get_groups_count = bcm6358_pinctrl_get_group_count, |
308 | }; |
309 | |
310 | static const struct pinmux_ops bcm6358_pmx_ops = { |
311 | .get_function_groups = bcm6358_pinctrl_get_groups, |
312 | .get_function_name = bcm6358_pinctrl_get_func_name, |
313 | .get_functions_count = bcm6358_pinctrl_get_func_count, |
314 | .gpio_request_enable = bcm6358_gpio_request_enable, |
315 | .set_mux = bcm6358_pinctrl_set_mux, |
316 | .strict = true, |
317 | }; |
318 | |
319 | static const struct bcm63xx_pinctrl_soc bcm6358_soc = { |
320 | .ngpios = BCM6358_NUM_GPIOS, |
321 | .npins = ARRAY_SIZE(bcm6358_pins), |
322 | .pctl_ops = &bcm6358_pctl_ops, |
323 | .pins = bcm6358_pins, |
324 | .pmx_ops = &bcm6358_pmx_ops, |
325 | }; |
326 | |
327 | static int bcm6358_pinctrl_probe(struct platform_device *pdev) |
328 | { |
329 | struct reg_field overlays = REG_FIELD(BCM6358_MODE_REG, 0, 15); |
330 | struct device *dev = &pdev->dev; |
331 | struct bcm63xx_pinctrl *pc; |
332 | struct bcm6358_priv *priv; |
333 | int err; |
334 | |
335 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
336 | if (!priv) |
337 | return -ENOMEM; |
338 | |
339 | err = bcm63xx_pinctrl_probe(pdev, soc: &bcm6358_soc, driver_data: (void *) priv); |
340 | if (err) |
341 | return err; |
342 | |
343 | pc = platform_get_drvdata(pdev); |
344 | |
345 | priv->overlays = devm_regmap_field_alloc(dev, regmap: pc->regs, reg_field: overlays); |
346 | if (IS_ERR(ptr: priv->overlays)) |
347 | return PTR_ERR(ptr: priv->overlays); |
348 | |
349 | return 0; |
350 | } |
351 | |
352 | static const struct of_device_id bcm6358_pinctrl_match[] = { |
353 | { .compatible = "brcm,bcm6358-pinctrl" , }, |
354 | { /* sentinel */ } |
355 | }; |
356 | |
357 | static struct platform_driver bcm6358_pinctrl_driver = { |
358 | .probe = bcm6358_pinctrl_probe, |
359 | .driver = { |
360 | .name = "bcm6358-pinctrl" , |
361 | .of_match_table = bcm6358_pinctrl_match, |
362 | }, |
363 | }; |
364 | |
365 | builtin_platform_driver(bcm6358_pinctrl_driver); |
366 | |