1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2015, Sony Mobile Communications AB. |
4 | * Copyright (c) 2013, The Linux Foundation. All rights reserved. |
5 | */ |
6 | |
7 | #include <linux/gpio/driver.h> |
8 | #include <linux/interrupt.h> |
9 | #include <linux/module.h> |
10 | #include <linux/of.h> |
11 | #include <linux/of_irq.h> |
12 | #include <linux/platform_device.h> |
13 | #include <linux/regmap.h> |
14 | #include <linux/seq_file.h> |
15 | #include <linux/slab.h> |
16 | |
17 | #include <linux/pinctrl/pinconf-generic.h> |
18 | #include <linux/pinctrl/pinconf.h> |
19 | #include <linux/pinctrl/pinctrl.h> |
20 | #include <linux/pinctrl/pinmux.h> |
21 | |
22 | #include <dt-bindings/pinctrl/qcom,pmic-gpio.h> |
23 | |
24 | #include "../core.h" |
25 | #include "../pinctrl-utils.h" |
26 | |
27 | /* mode */ |
28 | #define PM8XXX_GPIO_MODE_ENABLED BIT(0) |
29 | #define PM8XXX_GPIO_MODE_INPUT 0 |
30 | #define PM8XXX_GPIO_MODE_OUTPUT 2 |
31 | |
32 | /* output buffer */ |
33 | #define PM8XXX_GPIO_PUSH_PULL 0 |
34 | #define PM8XXX_GPIO_OPEN_DRAIN 1 |
35 | |
36 | /* bias */ |
37 | #define PM8XXX_GPIO_BIAS_PU_30 0 |
38 | #define PM8XXX_GPIO_BIAS_PU_1P5 1 |
39 | #define PM8XXX_GPIO_BIAS_PU_31P5 2 |
40 | #define PM8XXX_GPIO_BIAS_PU_1P5_30 3 |
41 | #define PM8XXX_GPIO_BIAS_PD 4 |
42 | #define PM8XXX_GPIO_BIAS_NP 5 |
43 | |
44 | /* GPIO registers */ |
45 | #define SSBI_REG_ADDR_GPIO_BASE 0x150 |
46 | #define SSBI_REG_ADDR_GPIO(n) (SSBI_REG_ADDR_GPIO_BASE + n) |
47 | |
48 | #define PM8XXX_BANK_WRITE BIT(7) |
49 | |
50 | #define PM8XXX_MAX_GPIOS 44 |
51 | |
52 | #define PM8XXX_GPIO_PHYSICAL_OFFSET 1 |
53 | |
54 | /* custom pinconf parameters */ |
55 | #define PM8XXX_QCOM_DRIVE_STRENGH (PIN_CONFIG_END + 1) |
56 | #define PM8XXX_QCOM_PULL_UP_STRENGTH (PIN_CONFIG_END + 2) |
57 | |
58 | /** |
59 | * struct pm8xxx_pin_data - dynamic configuration for a pin |
60 | * @reg: address of the control register |
61 | * @power_source: logical selected voltage source, mapping in static data |
62 | * is used translate to register values |
63 | * @mode: operating mode for the pin (input/output) |
64 | * @open_drain: output buffer configured as open-drain (vs push-pull) |
65 | * @output_value: configured output value |
66 | * @bias: register view of configured bias |
67 | * @pull_up_strength: placeholder for selected pull up strength |
68 | * only used to configure bias when pull up is selected |
69 | * @output_strength: selector of output-strength |
70 | * @disable: pin disabled / configured as tristate |
71 | * @function: pinmux selector |
72 | * @inverted: pin logic is inverted |
73 | */ |
74 | struct pm8xxx_pin_data { |
75 | unsigned reg; |
76 | u8 power_source; |
77 | u8 mode; |
78 | bool open_drain; |
79 | bool output_value; |
80 | u8 bias; |
81 | u8 pull_up_strength; |
82 | u8 output_strength; |
83 | bool disable; |
84 | u8 function; |
85 | bool inverted; |
86 | }; |
87 | |
88 | struct pm8xxx_gpio { |
89 | struct device *dev; |
90 | struct regmap *regmap; |
91 | struct pinctrl_dev *pctrl; |
92 | struct gpio_chip chip; |
93 | |
94 | struct pinctrl_desc desc; |
95 | unsigned npins; |
96 | }; |
97 | |
98 | static const struct pinconf_generic_params pm8xxx_gpio_bindings[] = { |
99 | {"qcom,drive-strength" , PM8XXX_QCOM_DRIVE_STRENGH, 0}, |
100 | {"qcom,pull-up-strength" , PM8XXX_QCOM_PULL_UP_STRENGTH, 0}, |
101 | }; |
102 | |
103 | #ifdef CONFIG_DEBUG_FS |
104 | static const struct pin_config_item pm8xxx_conf_items[ARRAY_SIZE(pm8xxx_gpio_bindings)] = { |
105 | PCONFDUMP(PM8XXX_QCOM_DRIVE_STRENGH, "drive-strength" , NULL, true), |
106 | PCONFDUMP(PM8XXX_QCOM_PULL_UP_STRENGTH, "pull up strength" , NULL, true), |
107 | }; |
108 | #endif |
109 | |
110 | static const char * const pm8xxx_groups[PM8XXX_MAX_GPIOS] = { |
111 | "gpio1" , "gpio2" , "gpio3" , "gpio4" , "gpio5" , "gpio6" , "gpio7" , "gpio8" , |
112 | "gpio9" , "gpio10" , "gpio11" , "gpio12" , "gpio13" , "gpio14" , "gpio15" , |
113 | "gpio16" , "gpio17" , "gpio18" , "gpio19" , "gpio20" , "gpio21" , "gpio22" , |
114 | "gpio23" , "gpio24" , "gpio25" , "gpio26" , "gpio27" , "gpio28" , "gpio29" , |
115 | "gpio30" , "gpio31" , "gpio32" , "gpio33" , "gpio34" , "gpio35" , "gpio36" , |
116 | "gpio37" , "gpio38" , "gpio39" , "gpio40" , "gpio41" , "gpio42" , "gpio43" , |
117 | "gpio44" , |
118 | }; |
119 | |
120 | static const char * const pm8xxx_gpio_functions[] = { |
121 | PMIC_GPIO_FUNC_NORMAL, PMIC_GPIO_FUNC_PAIRED, |
122 | PMIC_GPIO_FUNC_FUNC1, PMIC_GPIO_FUNC_FUNC2, |
123 | PMIC_GPIO_FUNC_DTEST1, PMIC_GPIO_FUNC_DTEST2, |
124 | PMIC_GPIO_FUNC_DTEST3, PMIC_GPIO_FUNC_DTEST4, |
125 | }; |
126 | |
127 | static int pm8xxx_read_bank(struct pm8xxx_gpio *pctrl, |
128 | struct pm8xxx_pin_data *pin, int bank) |
129 | { |
130 | unsigned int val = bank << 4; |
131 | int ret; |
132 | |
133 | ret = regmap_write(map: pctrl->regmap, reg: pin->reg, val); |
134 | if (ret) { |
135 | dev_err(pctrl->dev, "failed to select bank %d\n" , bank); |
136 | return ret; |
137 | } |
138 | |
139 | ret = regmap_read(map: pctrl->regmap, reg: pin->reg, val: &val); |
140 | if (ret) { |
141 | dev_err(pctrl->dev, "failed to read register %d\n" , bank); |
142 | return ret; |
143 | } |
144 | |
145 | return val; |
146 | } |
147 | |
148 | static int pm8xxx_write_bank(struct pm8xxx_gpio *pctrl, |
149 | struct pm8xxx_pin_data *pin, |
150 | int bank, |
151 | u8 val) |
152 | { |
153 | int ret; |
154 | |
155 | val |= PM8XXX_BANK_WRITE; |
156 | val |= bank << 4; |
157 | |
158 | ret = regmap_write(map: pctrl->regmap, reg: pin->reg, val); |
159 | if (ret) |
160 | dev_err(pctrl->dev, "failed to write register\n" ); |
161 | |
162 | return ret; |
163 | } |
164 | |
165 | static int pm8xxx_get_groups_count(struct pinctrl_dev *pctldev) |
166 | { |
167 | struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); |
168 | |
169 | return pctrl->npins; |
170 | } |
171 | |
172 | static const char *pm8xxx_get_group_name(struct pinctrl_dev *pctldev, |
173 | unsigned group) |
174 | { |
175 | return pm8xxx_groups[group]; |
176 | } |
177 | |
178 | |
179 | static int pm8xxx_get_group_pins(struct pinctrl_dev *pctldev, |
180 | unsigned group, |
181 | const unsigned **pins, |
182 | unsigned *num_pins) |
183 | { |
184 | struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); |
185 | |
186 | *pins = &pctrl->desc.pins[group].number; |
187 | *num_pins = 1; |
188 | |
189 | return 0; |
190 | } |
191 | |
192 | static const struct pinctrl_ops pm8xxx_pinctrl_ops = { |
193 | .get_groups_count = pm8xxx_get_groups_count, |
194 | .get_group_name = pm8xxx_get_group_name, |
195 | .get_group_pins = pm8xxx_get_group_pins, |
196 | .dt_node_to_map = pinconf_generic_dt_node_to_map_group, |
197 | .dt_free_map = pinctrl_utils_free_map, |
198 | }; |
199 | |
200 | static int pm8xxx_get_functions_count(struct pinctrl_dev *pctldev) |
201 | { |
202 | return ARRAY_SIZE(pm8xxx_gpio_functions); |
203 | } |
204 | |
205 | static const char *pm8xxx_get_function_name(struct pinctrl_dev *pctldev, |
206 | unsigned function) |
207 | { |
208 | return pm8xxx_gpio_functions[function]; |
209 | } |
210 | |
211 | static int pm8xxx_get_function_groups(struct pinctrl_dev *pctldev, |
212 | unsigned function, |
213 | const char * const **groups, |
214 | unsigned * const num_groups) |
215 | { |
216 | struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); |
217 | |
218 | *groups = pm8xxx_groups; |
219 | *num_groups = pctrl->npins; |
220 | return 0; |
221 | } |
222 | |
223 | static int pm8xxx_pinmux_set_mux(struct pinctrl_dev *pctldev, |
224 | unsigned function, |
225 | unsigned group) |
226 | { |
227 | struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); |
228 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[group].drv_data; |
229 | u8 val; |
230 | |
231 | pin->function = function; |
232 | val = pin->function << 1; |
233 | |
234 | pm8xxx_write_bank(pctrl, pin, bank: 4, val); |
235 | |
236 | return 0; |
237 | } |
238 | |
239 | static const struct pinmux_ops pm8xxx_pinmux_ops = { |
240 | .get_functions_count = pm8xxx_get_functions_count, |
241 | .get_function_name = pm8xxx_get_function_name, |
242 | .get_function_groups = pm8xxx_get_function_groups, |
243 | .set_mux = pm8xxx_pinmux_set_mux, |
244 | }; |
245 | |
246 | static int pm8xxx_pin_config_get(struct pinctrl_dev *pctldev, |
247 | unsigned int offset, |
248 | unsigned long *config) |
249 | { |
250 | struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); |
251 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; |
252 | unsigned param = pinconf_to_config_param(config: *config); |
253 | unsigned arg; |
254 | |
255 | switch (param) { |
256 | case PIN_CONFIG_BIAS_DISABLE: |
257 | if (pin->bias != PM8XXX_GPIO_BIAS_NP) |
258 | return -EINVAL; |
259 | arg = 1; |
260 | break; |
261 | case PIN_CONFIG_BIAS_PULL_DOWN: |
262 | if (pin->bias != PM8XXX_GPIO_BIAS_PD) |
263 | return -EINVAL; |
264 | arg = 1; |
265 | break; |
266 | case PIN_CONFIG_BIAS_PULL_UP: |
267 | if (pin->bias > PM8XXX_GPIO_BIAS_PU_1P5_30) |
268 | return -EINVAL; |
269 | arg = 1; |
270 | break; |
271 | case PM8XXX_QCOM_PULL_UP_STRENGTH: |
272 | arg = pin->pull_up_strength; |
273 | break; |
274 | case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: |
275 | if (!pin->disable) |
276 | return -EINVAL; |
277 | arg = 1; |
278 | break; |
279 | case PIN_CONFIG_INPUT_ENABLE: |
280 | if (pin->mode != PM8XXX_GPIO_MODE_INPUT) |
281 | return -EINVAL; |
282 | arg = 1; |
283 | break; |
284 | case PIN_CONFIG_OUTPUT: |
285 | if (pin->mode & PM8XXX_GPIO_MODE_OUTPUT) |
286 | arg = pin->output_value; |
287 | else |
288 | arg = 0; |
289 | break; |
290 | case PIN_CONFIG_POWER_SOURCE: |
291 | arg = pin->power_source; |
292 | break; |
293 | case PM8XXX_QCOM_DRIVE_STRENGH: |
294 | arg = pin->output_strength; |
295 | break; |
296 | case PIN_CONFIG_DRIVE_PUSH_PULL: |
297 | if (pin->open_drain) |
298 | return -EINVAL; |
299 | arg = 1; |
300 | break; |
301 | case PIN_CONFIG_DRIVE_OPEN_DRAIN: |
302 | if (!pin->open_drain) |
303 | return -EINVAL; |
304 | arg = 1; |
305 | break; |
306 | default: |
307 | return -EINVAL; |
308 | } |
309 | |
310 | *config = pinconf_to_config_packed(param, argument: arg); |
311 | |
312 | return 0; |
313 | } |
314 | |
315 | static int pm8xxx_pin_config_set(struct pinctrl_dev *pctldev, |
316 | unsigned int offset, |
317 | unsigned long *configs, |
318 | unsigned num_configs) |
319 | { |
320 | struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); |
321 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; |
322 | unsigned param; |
323 | unsigned arg; |
324 | unsigned i; |
325 | u8 banks = 0; |
326 | u8 val; |
327 | |
328 | for (i = 0; i < num_configs; i++) { |
329 | param = pinconf_to_config_param(config: configs[i]); |
330 | arg = pinconf_to_config_argument(config: configs[i]); |
331 | |
332 | switch (param) { |
333 | case PIN_CONFIG_BIAS_DISABLE: |
334 | pin->bias = PM8XXX_GPIO_BIAS_NP; |
335 | banks |= BIT(2); |
336 | pin->disable = 0; |
337 | banks |= BIT(3); |
338 | break; |
339 | case PIN_CONFIG_BIAS_PULL_DOWN: |
340 | pin->bias = PM8XXX_GPIO_BIAS_PD; |
341 | banks |= BIT(2); |
342 | pin->disable = 0; |
343 | banks |= BIT(3); |
344 | break; |
345 | case PM8XXX_QCOM_PULL_UP_STRENGTH: |
346 | if (arg > PM8XXX_GPIO_BIAS_PU_1P5_30) { |
347 | dev_err(pctrl->dev, "invalid pull-up strength\n" ); |
348 | return -EINVAL; |
349 | } |
350 | pin->pull_up_strength = arg; |
351 | fallthrough; |
352 | case PIN_CONFIG_BIAS_PULL_UP: |
353 | pin->bias = pin->pull_up_strength; |
354 | banks |= BIT(2); |
355 | pin->disable = 0; |
356 | banks |= BIT(3); |
357 | break; |
358 | case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: |
359 | pin->disable = 1; |
360 | banks |= BIT(3); |
361 | break; |
362 | case PIN_CONFIG_INPUT_ENABLE: |
363 | pin->mode = PM8XXX_GPIO_MODE_INPUT; |
364 | banks |= BIT(0) | BIT(1); |
365 | break; |
366 | case PIN_CONFIG_OUTPUT: |
367 | pin->mode = PM8XXX_GPIO_MODE_OUTPUT; |
368 | pin->output_value = !!arg; |
369 | banks |= BIT(0) | BIT(1); |
370 | break; |
371 | case PIN_CONFIG_POWER_SOURCE: |
372 | pin->power_source = arg; |
373 | banks |= BIT(0); |
374 | break; |
375 | case PM8XXX_QCOM_DRIVE_STRENGH: |
376 | if (arg > PMIC_GPIO_STRENGTH_LOW) { |
377 | dev_err(pctrl->dev, "invalid drive strength\n" ); |
378 | return -EINVAL; |
379 | } |
380 | pin->output_strength = arg; |
381 | banks |= BIT(3); |
382 | break; |
383 | case PIN_CONFIG_DRIVE_PUSH_PULL: |
384 | pin->open_drain = 0; |
385 | banks |= BIT(1); |
386 | break; |
387 | case PIN_CONFIG_DRIVE_OPEN_DRAIN: |
388 | pin->open_drain = 1; |
389 | banks |= BIT(1); |
390 | break; |
391 | default: |
392 | dev_err(pctrl->dev, |
393 | "unsupported config parameter: %x\n" , |
394 | param); |
395 | return -EINVAL; |
396 | } |
397 | } |
398 | |
399 | if (banks & BIT(0)) { |
400 | val = pin->power_source << 1; |
401 | val |= PM8XXX_GPIO_MODE_ENABLED; |
402 | pm8xxx_write_bank(pctrl, pin, bank: 0, val); |
403 | } |
404 | |
405 | if (banks & BIT(1)) { |
406 | val = pin->mode << 2; |
407 | val |= pin->open_drain << 1; |
408 | val |= pin->output_value; |
409 | pm8xxx_write_bank(pctrl, pin, bank: 1, val); |
410 | } |
411 | |
412 | if (banks & BIT(2)) { |
413 | val = pin->bias << 1; |
414 | pm8xxx_write_bank(pctrl, pin, bank: 2, val); |
415 | } |
416 | |
417 | if (banks & BIT(3)) { |
418 | val = pin->output_strength << 2; |
419 | val |= pin->disable; |
420 | pm8xxx_write_bank(pctrl, pin, bank: 3, val); |
421 | } |
422 | |
423 | if (banks & BIT(4)) { |
424 | val = pin->function << 1; |
425 | pm8xxx_write_bank(pctrl, pin, bank: 4, val); |
426 | } |
427 | |
428 | if (banks & BIT(5)) { |
429 | val = 0; |
430 | if (!pin->inverted) |
431 | val |= BIT(3); |
432 | pm8xxx_write_bank(pctrl, pin, bank: 5, val); |
433 | } |
434 | |
435 | return 0; |
436 | } |
437 | |
438 | static const struct pinconf_ops pm8xxx_pinconf_ops = { |
439 | .is_generic = true, |
440 | .pin_config_group_get = pm8xxx_pin_config_get, |
441 | .pin_config_group_set = pm8xxx_pin_config_set, |
442 | }; |
443 | |
444 | static const struct pinctrl_desc pm8xxx_pinctrl_desc = { |
445 | .name = "pm8xxx_gpio" , |
446 | .pctlops = &pm8xxx_pinctrl_ops, |
447 | .pmxops = &pm8xxx_pinmux_ops, |
448 | .confops = &pm8xxx_pinconf_ops, |
449 | .owner = THIS_MODULE, |
450 | }; |
451 | |
452 | static int pm8xxx_gpio_direction_input(struct gpio_chip *chip, |
453 | unsigned offset) |
454 | { |
455 | struct pm8xxx_gpio *pctrl = gpiochip_get_data(gc: chip); |
456 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; |
457 | u8 val; |
458 | |
459 | pin->mode = PM8XXX_GPIO_MODE_INPUT; |
460 | val = pin->mode << 2; |
461 | |
462 | pm8xxx_write_bank(pctrl, pin, bank: 1, val); |
463 | |
464 | return 0; |
465 | } |
466 | |
467 | static int pm8xxx_gpio_direction_output(struct gpio_chip *chip, |
468 | unsigned offset, |
469 | int value) |
470 | { |
471 | struct pm8xxx_gpio *pctrl = gpiochip_get_data(gc: chip); |
472 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; |
473 | u8 val; |
474 | |
475 | pin->mode = PM8XXX_GPIO_MODE_OUTPUT; |
476 | pin->output_value = !!value; |
477 | |
478 | val = pin->mode << 2; |
479 | val |= pin->open_drain << 1; |
480 | val |= pin->output_value; |
481 | |
482 | pm8xxx_write_bank(pctrl, pin, bank: 1, val); |
483 | |
484 | return 0; |
485 | } |
486 | |
487 | static int pm8xxx_gpio_get(struct gpio_chip *chip, unsigned offset) |
488 | { |
489 | struct pm8xxx_gpio *pctrl = gpiochip_get_data(gc: chip); |
490 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; |
491 | int ret, irq; |
492 | bool state; |
493 | |
494 | if (pin->mode == PM8XXX_GPIO_MODE_OUTPUT) |
495 | return pin->output_value; |
496 | |
497 | irq = chip->to_irq(chip, offset); |
498 | if (irq >= 0) { |
499 | ret = irq_get_irqchip_state(irq, which: IRQCHIP_STATE_LINE_LEVEL, |
500 | state: &state); |
501 | if (!ret) |
502 | ret = !!state; |
503 | } else |
504 | ret = -EINVAL; |
505 | |
506 | return ret; |
507 | } |
508 | |
509 | static void pm8xxx_gpio_set(struct gpio_chip *chip, unsigned offset, int value) |
510 | { |
511 | struct pm8xxx_gpio *pctrl = gpiochip_get_data(gc: chip); |
512 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; |
513 | u8 val; |
514 | |
515 | pin->output_value = !!value; |
516 | |
517 | val = pin->mode << 2; |
518 | val |= pin->open_drain << 1; |
519 | val |= pin->output_value; |
520 | |
521 | pm8xxx_write_bank(pctrl, pin, bank: 1, val); |
522 | } |
523 | |
524 | static int pm8xxx_gpio_of_xlate(struct gpio_chip *chip, |
525 | const struct of_phandle_args *gpio_desc, |
526 | u32 *flags) |
527 | { |
528 | if (chip->of_gpio_n_cells < 2) |
529 | return -EINVAL; |
530 | |
531 | if (flags) |
532 | *flags = gpio_desc->args[1]; |
533 | |
534 | return gpio_desc->args[0] - PM8XXX_GPIO_PHYSICAL_OFFSET; |
535 | } |
536 | |
537 | |
538 | #ifdef CONFIG_DEBUG_FS |
539 | |
540 | static void pm8xxx_gpio_dbg_show_one(struct seq_file *s, |
541 | struct pinctrl_dev *pctldev, |
542 | struct gpio_chip *chip, |
543 | unsigned offset, |
544 | unsigned gpio) |
545 | { |
546 | struct pm8xxx_gpio *pctrl = gpiochip_get_data(gc: chip); |
547 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; |
548 | |
549 | static const char * const modes[] = { |
550 | "in" , "both" , "out" , "off" |
551 | }; |
552 | static const char * const biases[] = { |
553 | "pull-up 30uA" , "pull-up 1.5uA" , "pull-up 31.5uA" , |
554 | "pull-up 1.5uA + 30uA boost" , "pull-down 10uA" , "no pull" |
555 | }; |
556 | static const char * const buffer_types[] = { |
557 | "push-pull" , "open-drain" |
558 | }; |
559 | static const char * const strengths[] = { |
560 | "no" , "high" , "medium" , "low" |
561 | }; |
562 | |
563 | seq_printf(m: s, fmt: " gpio%-2d:" , offset + PM8XXX_GPIO_PHYSICAL_OFFSET); |
564 | if (pin->disable) { |
565 | seq_puts(m: s, s: " ---" ); |
566 | } else { |
567 | seq_printf(m: s, fmt: " %-4s" , modes[pin->mode]); |
568 | seq_printf(m: s, fmt: " %-7s" , pm8xxx_gpio_functions[pin->function]); |
569 | seq_printf(m: s, fmt: " VIN%d" , pin->power_source); |
570 | seq_printf(m: s, fmt: " %-27s" , biases[pin->bias]); |
571 | seq_printf(m: s, fmt: " %-10s" , buffer_types[pin->open_drain]); |
572 | seq_printf(m: s, fmt: " %-4s" , pin->output_value ? "high" : "low" ); |
573 | seq_printf(m: s, fmt: " %-7s" , strengths[pin->output_strength]); |
574 | if (pin->inverted) |
575 | seq_puts(m: s, s: " inverted" ); |
576 | } |
577 | } |
578 | |
579 | static void pm8xxx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) |
580 | { |
581 | unsigned gpio = chip->base; |
582 | unsigned i; |
583 | |
584 | for (i = 0; i < chip->ngpio; i++, gpio++) { |
585 | pm8xxx_gpio_dbg_show_one(s, NULL, chip, offset: i, gpio); |
586 | seq_puts(m: s, s: "\n" ); |
587 | } |
588 | } |
589 | |
590 | #else |
591 | #define pm8xxx_gpio_dbg_show NULL |
592 | #endif |
593 | |
594 | static const struct gpio_chip pm8xxx_gpio_template = { |
595 | .direction_input = pm8xxx_gpio_direction_input, |
596 | .direction_output = pm8xxx_gpio_direction_output, |
597 | .get = pm8xxx_gpio_get, |
598 | .set = pm8xxx_gpio_set, |
599 | .of_xlate = pm8xxx_gpio_of_xlate, |
600 | .dbg_show = pm8xxx_gpio_dbg_show, |
601 | .owner = THIS_MODULE, |
602 | }; |
603 | |
604 | static int pm8xxx_pin_populate(struct pm8xxx_gpio *pctrl, |
605 | struct pm8xxx_pin_data *pin) |
606 | { |
607 | int val; |
608 | |
609 | val = pm8xxx_read_bank(pctrl, pin, bank: 0); |
610 | if (val < 0) |
611 | return val; |
612 | |
613 | pin->power_source = (val >> 1) & 0x7; |
614 | |
615 | val = pm8xxx_read_bank(pctrl, pin, bank: 1); |
616 | if (val < 0) |
617 | return val; |
618 | |
619 | pin->mode = (val >> 2) & 0x3; |
620 | pin->open_drain = !!(val & BIT(1)); |
621 | pin->output_value = val & BIT(0); |
622 | |
623 | val = pm8xxx_read_bank(pctrl, pin, bank: 2); |
624 | if (val < 0) |
625 | return val; |
626 | |
627 | pin->bias = (val >> 1) & 0x7; |
628 | if (pin->bias <= PM8XXX_GPIO_BIAS_PU_1P5_30) |
629 | pin->pull_up_strength = pin->bias; |
630 | else |
631 | pin->pull_up_strength = PM8XXX_GPIO_BIAS_PU_30; |
632 | |
633 | val = pm8xxx_read_bank(pctrl, pin, bank: 3); |
634 | if (val < 0) |
635 | return val; |
636 | |
637 | pin->output_strength = (val >> 2) & 0x3; |
638 | pin->disable = val & BIT(0); |
639 | |
640 | val = pm8xxx_read_bank(pctrl, pin, bank: 4); |
641 | if (val < 0) |
642 | return val; |
643 | |
644 | pin->function = (val >> 1) & 0x7; |
645 | |
646 | val = pm8xxx_read_bank(pctrl, pin, bank: 5); |
647 | if (val < 0) |
648 | return val; |
649 | |
650 | pin->inverted = !(val & BIT(3)); |
651 | |
652 | return 0; |
653 | } |
654 | |
655 | static void pm8xxx_irq_disable(struct irq_data *d) |
656 | { |
657 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
658 | |
659 | gpiochip_disable_irq(gc, offset: irqd_to_hwirq(d)); |
660 | } |
661 | |
662 | static void pm8xxx_irq_enable(struct irq_data *d) |
663 | { |
664 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
665 | |
666 | gpiochip_enable_irq(gc, offset: irqd_to_hwirq(d)); |
667 | } |
668 | |
669 | static const struct irq_chip pm8xxx_irq_chip = { |
670 | .name = "ssbi-gpio" , |
671 | .irq_mask_ack = irq_chip_mask_ack_parent, |
672 | .irq_unmask = irq_chip_unmask_parent, |
673 | .irq_disable = pm8xxx_irq_disable, |
674 | .irq_enable = pm8xxx_irq_enable, |
675 | .irq_set_type = irq_chip_set_type_parent, |
676 | .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE | |
677 | IRQCHIP_IMMUTABLE, |
678 | GPIOCHIP_IRQ_RESOURCE_HELPERS, |
679 | }; |
680 | |
681 | static int pm8xxx_domain_translate(struct irq_domain *domain, |
682 | struct irq_fwspec *fwspec, |
683 | unsigned long *hwirq, |
684 | unsigned int *type) |
685 | { |
686 | struct pm8xxx_gpio *pctrl = container_of(domain->host_data, |
687 | struct pm8xxx_gpio, chip); |
688 | |
689 | if (fwspec->param_count != 2 || fwspec->param[0] < 1 || |
690 | fwspec->param[0] > pctrl->chip.ngpio) |
691 | return -EINVAL; |
692 | |
693 | *hwirq = fwspec->param[0] - PM8XXX_GPIO_PHYSICAL_OFFSET; |
694 | *type = fwspec->param[1]; |
695 | |
696 | return 0; |
697 | } |
698 | |
699 | static unsigned int pm8xxx_child_offset_to_irq(struct gpio_chip *chip, |
700 | unsigned int offset) |
701 | { |
702 | return offset + PM8XXX_GPIO_PHYSICAL_OFFSET; |
703 | } |
704 | |
705 | static int pm8xxx_child_to_parent_hwirq(struct gpio_chip *chip, |
706 | unsigned int child_hwirq, |
707 | unsigned int child_type, |
708 | unsigned int *parent_hwirq, |
709 | unsigned int *parent_type) |
710 | { |
711 | *parent_hwirq = child_hwirq + 0xc0; |
712 | *parent_type = child_type; |
713 | |
714 | return 0; |
715 | } |
716 | |
717 | static const struct of_device_id pm8xxx_gpio_of_match[] = { |
718 | { .compatible = "qcom,pm8018-gpio" , .data = (void *) 6 }, |
719 | { .compatible = "qcom,pm8038-gpio" , .data = (void *) 12 }, |
720 | { .compatible = "qcom,pm8058-gpio" , .data = (void *) 44 }, |
721 | { .compatible = "qcom,pm8917-gpio" , .data = (void *) 38 }, |
722 | { .compatible = "qcom,pm8921-gpio" , .data = (void *) 44 }, |
723 | { }, |
724 | }; |
725 | MODULE_DEVICE_TABLE(of, pm8xxx_gpio_of_match); |
726 | |
727 | static int pm8xxx_gpio_probe(struct platform_device *pdev) |
728 | { |
729 | struct pm8xxx_pin_data *pin_data; |
730 | struct irq_domain *parent_domain; |
731 | struct device_node *parent_node; |
732 | struct pinctrl_pin_desc *pins; |
733 | struct gpio_irq_chip *girq; |
734 | struct pm8xxx_gpio *pctrl; |
735 | int ret, i; |
736 | |
737 | pctrl = devm_kzalloc(dev: &pdev->dev, size: sizeof(*pctrl), GFP_KERNEL); |
738 | if (!pctrl) |
739 | return -ENOMEM; |
740 | |
741 | pctrl->dev = &pdev->dev; |
742 | pctrl->npins = (uintptr_t) device_get_match_data(dev: &pdev->dev); |
743 | |
744 | pctrl->regmap = dev_get_regmap(dev: pdev->dev.parent, NULL); |
745 | if (!pctrl->regmap) { |
746 | dev_err(&pdev->dev, "parent regmap unavailable\n" ); |
747 | return -ENXIO; |
748 | } |
749 | |
750 | pctrl->desc = pm8xxx_pinctrl_desc; |
751 | pctrl->desc.npins = pctrl->npins; |
752 | |
753 | pins = devm_kcalloc(dev: &pdev->dev, |
754 | n: pctrl->desc.npins, |
755 | size: sizeof(struct pinctrl_pin_desc), |
756 | GFP_KERNEL); |
757 | if (!pins) |
758 | return -ENOMEM; |
759 | |
760 | pin_data = devm_kcalloc(dev: &pdev->dev, |
761 | n: pctrl->desc.npins, |
762 | size: sizeof(struct pm8xxx_pin_data), |
763 | GFP_KERNEL); |
764 | if (!pin_data) |
765 | return -ENOMEM; |
766 | |
767 | for (i = 0; i < pctrl->desc.npins; i++) { |
768 | pin_data[i].reg = SSBI_REG_ADDR_GPIO(i); |
769 | |
770 | ret = pm8xxx_pin_populate(pctrl, pin: &pin_data[i]); |
771 | if (ret) |
772 | return ret; |
773 | |
774 | pins[i].number = i; |
775 | pins[i].name = pm8xxx_groups[i]; |
776 | pins[i].drv_data = &pin_data[i]; |
777 | } |
778 | pctrl->desc.pins = pins; |
779 | |
780 | pctrl->desc.num_custom_params = ARRAY_SIZE(pm8xxx_gpio_bindings); |
781 | pctrl->desc.custom_params = pm8xxx_gpio_bindings; |
782 | #ifdef CONFIG_DEBUG_FS |
783 | pctrl->desc.custom_conf_items = pm8xxx_conf_items; |
784 | #endif |
785 | |
786 | pctrl->pctrl = devm_pinctrl_register(dev: &pdev->dev, pctldesc: &pctrl->desc, driver_data: pctrl); |
787 | if (IS_ERR(ptr: pctrl->pctrl)) { |
788 | dev_err(&pdev->dev, "couldn't register pm8xxx gpio driver\n" ); |
789 | return PTR_ERR(ptr: pctrl->pctrl); |
790 | } |
791 | |
792 | pctrl->chip = pm8xxx_gpio_template; |
793 | pctrl->chip.base = -1; |
794 | pctrl->chip.parent = &pdev->dev; |
795 | pctrl->chip.of_gpio_n_cells = 2; |
796 | pctrl->chip.label = dev_name(dev: pctrl->dev); |
797 | pctrl->chip.ngpio = pctrl->npins; |
798 | |
799 | parent_node = of_irq_find_parent(child: pctrl->dev->of_node); |
800 | if (!parent_node) |
801 | return -ENXIO; |
802 | |
803 | parent_domain = irq_find_host(node: parent_node); |
804 | of_node_put(node: parent_node); |
805 | if (!parent_domain) |
806 | return -ENXIO; |
807 | |
808 | girq = &pctrl->chip.irq; |
809 | gpio_irq_chip_set_chip(girq, chip: &pm8xxx_irq_chip); |
810 | girq->default_type = IRQ_TYPE_NONE; |
811 | girq->handler = handle_level_irq; |
812 | girq->fwnode = dev_fwnode(pctrl->dev); |
813 | girq->parent_domain = parent_domain; |
814 | girq->child_to_parent_hwirq = pm8xxx_child_to_parent_hwirq; |
815 | girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_twocell; |
816 | girq->child_offset_to_irq = pm8xxx_child_offset_to_irq; |
817 | girq->child_irq_domain_ops.translate = pm8xxx_domain_translate; |
818 | |
819 | ret = gpiochip_add_data(&pctrl->chip, pctrl); |
820 | if (ret) { |
821 | dev_err(&pdev->dev, "failed register gpiochip\n" ); |
822 | return ret; |
823 | } |
824 | |
825 | /* |
826 | * For DeviceTree-supported systems, the gpio core checks the |
827 | * pinctrl's device node for the "gpio-ranges" property. |
828 | * If it is present, it takes care of adding the pin ranges |
829 | * for the driver. In this case the driver can skip ahead. |
830 | * |
831 | * In order to remain compatible with older, existing DeviceTree |
832 | * files which don't set the "gpio-ranges" property or systems that |
833 | * utilize ACPI the driver has to call gpiochip_add_pin_range(). |
834 | */ |
835 | if (!of_property_read_bool(np: pctrl->dev->of_node, propname: "gpio-ranges" )) { |
836 | ret = gpiochip_add_pin_range(gc: &pctrl->chip, pinctl_name: dev_name(dev: pctrl->dev), |
837 | gpio_offset: 0, pin_offset: 0, npins: pctrl->chip.ngpio); |
838 | if (ret) { |
839 | dev_err(pctrl->dev, "failed to add pin range\n" ); |
840 | goto unregister_gpiochip; |
841 | } |
842 | } |
843 | |
844 | platform_set_drvdata(pdev, data: pctrl); |
845 | |
846 | dev_dbg(&pdev->dev, "Qualcomm pm8xxx gpio driver probed\n" ); |
847 | |
848 | return 0; |
849 | |
850 | unregister_gpiochip: |
851 | gpiochip_remove(gc: &pctrl->chip); |
852 | |
853 | return ret; |
854 | } |
855 | |
856 | static void pm8xxx_gpio_remove(struct platform_device *pdev) |
857 | { |
858 | struct pm8xxx_gpio *pctrl = platform_get_drvdata(pdev); |
859 | |
860 | gpiochip_remove(gc: &pctrl->chip); |
861 | } |
862 | |
863 | static struct platform_driver pm8xxx_gpio_driver = { |
864 | .driver = { |
865 | .name = "qcom-ssbi-gpio" , |
866 | .of_match_table = pm8xxx_gpio_of_match, |
867 | }, |
868 | .probe = pm8xxx_gpio_probe, |
869 | .remove_new = pm8xxx_gpio_remove, |
870 | }; |
871 | |
872 | module_platform_driver(pm8xxx_gpio_driver); |
873 | |
874 | MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>" ); |
875 | MODULE_DESCRIPTION("Qualcomm PM8xxx GPIO driver" ); |
876 | MODULE_LICENSE("GPL v2" ); |
877 | |