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-mpp.h> |
23 | |
24 | #include "../core.h" |
25 | #include "../pinctrl-utils.h" |
26 | |
27 | /* MPP registers */ |
28 | #define SSBI_REG_ADDR_MPP_BASE 0x50 |
29 | #define SSBI_REG_ADDR_MPP(n) (SSBI_REG_ADDR_MPP_BASE + n) |
30 | |
31 | /* MPP Type: type */ |
32 | #define PM8XXX_MPP_TYPE_D_INPUT 0 |
33 | #define PM8XXX_MPP_TYPE_D_OUTPUT 1 |
34 | #define PM8XXX_MPP_TYPE_D_BI_DIR 2 |
35 | #define PM8XXX_MPP_TYPE_A_INPUT 3 |
36 | #define PM8XXX_MPP_TYPE_A_OUTPUT 4 |
37 | #define PM8XXX_MPP_TYPE_SINK 5 |
38 | #define PM8XXX_MPP_TYPE_DTEST_SINK 6 |
39 | #define PM8XXX_MPP_TYPE_DTEST_OUTPUT 7 |
40 | |
41 | /* Digital Input: control */ |
42 | #define PM8XXX_MPP_DIN_TO_INT 0 |
43 | #define PM8XXX_MPP_DIN_TO_DBUS1 1 |
44 | #define PM8XXX_MPP_DIN_TO_DBUS2 2 |
45 | #define PM8XXX_MPP_DIN_TO_DBUS3 3 |
46 | |
47 | /* Digital Output: control */ |
48 | #define PM8XXX_MPP_DOUT_CTRL_LOW 0 |
49 | #define PM8XXX_MPP_DOUT_CTRL_HIGH 1 |
50 | #define PM8XXX_MPP_DOUT_CTRL_MPP 2 |
51 | #define PM8XXX_MPP_DOUT_CTRL_INV_MPP 3 |
52 | |
53 | /* Bidirectional: control */ |
54 | #define PM8XXX_MPP_BI_PULLUP_1KOHM 0 |
55 | #define PM8XXX_MPP_BI_PULLUP_OPEN 1 |
56 | #define PM8XXX_MPP_BI_PULLUP_10KOHM 2 |
57 | #define PM8XXX_MPP_BI_PULLUP_30KOHM 3 |
58 | |
59 | /* Analog Output: control */ |
60 | #define PM8XXX_MPP_AOUT_CTRL_DISABLE 0 |
61 | #define PM8XXX_MPP_AOUT_CTRL_ENABLE 1 |
62 | #define PM8XXX_MPP_AOUT_CTRL_MPP_HIGH_EN 2 |
63 | #define PM8XXX_MPP_AOUT_CTRL_MPP_LOW_EN 3 |
64 | |
65 | /* Current Sink: control */ |
66 | #define PM8XXX_MPP_CS_CTRL_DISABLE 0 |
67 | #define PM8XXX_MPP_CS_CTRL_ENABLE 1 |
68 | #define PM8XXX_MPP_CS_CTRL_MPP_HIGH_EN 2 |
69 | #define PM8XXX_MPP_CS_CTRL_MPP_LOW_EN 3 |
70 | |
71 | /* DTEST Current Sink: control */ |
72 | #define PM8XXX_MPP_DTEST_CS_CTRL_EN1 0 |
73 | #define PM8XXX_MPP_DTEST_CS_CTRL_EN2 1 |
74 | #define PM8XXX_MPP_DTEST_CS_CTRL_EN3 2 |
75 | #define PM8XXX_MPP_DTEST_CS_CTRL_EN4 3 |
76 | |
77 | /* DTEST Digital Output: control */ |
78 | #define PM8XXX_MPP_DTEST_DBUS1 0 |
79 | #define PM8XXX_MPP_DTEST_DBUS2 1 |
80 | #define PM8XXX_MPP_DTEST_DBUS3 2 |
81 | #define PM8XXX_MPP_DTEST_DBUS4 3 |
82 | |
83 | /* custom pinconf parameters */ |
84 | #define PM8XXX_CONFIG_AMUX (PIN_CONFIG_END + 1) |
85 | #define PM8XXX_CONFIG_DTEST_SELECTOR (PIN_CONFIG_END + 2) |
86 | #define PM8XXX_CONFIG_ALEVEL (PIN_CONFIG_END + 3) |
87 | #define PM8XXX_CONFIG_PAIRED (PIN_CONFIG_END + 4) |
88 | |
89 | /** |
90 | * struct pm8xxx_pin_data - dynamic configuration for a pin |
91 | * @reg: address of the control register |
92 | * @mode: operating mode for the pin (digital, analog or current sink) |
93 | * @input: pin is input |
94 | * @output: pin is output |
95 | * @high_z: pin is floating |
96 | * @paired: mpp operates in paired mode |
97 | * @output_value: logical output value of the mpp |
98 | * @power_source: selected power source |
99 | * @dtest: DTEST route selector |
100 | * @amux: input muxing in analog mode |
101 | * @aout_level: selector of the output in analog mode |
102 | * @drive_strength: drive strength of the current sink |
103 | * @pullup: pull up value, when in digital bidirectional mode |
104 | */ |
105 | struct pm8xxx_pin_data { |
106 | unsigned reg; |
107 | |
108 | u8 mode; |
109 | |
110 | bool input; |
111 | bool output; |
112 | bool high_z; |
113 | bool paired; |
114 | bool output_value; |
115 | |
116 | u8 power_source; |
117 | u8 dtest; |
118 | u8 amux; |
119 | u8 aout_level; |
120 | u8 drive_strength; |
121 | unsigned pullup; |
122 | }; |
123 | |
124 | struct pm8xxx_mpp { |
125 | struct device *dev; |
126 | struct regmap *regmap; |
127 | struct pinctrl_dev *pctrl; |
128 | struct gpio_chip chip; |
129 | |
130 | struct pinctrl_desc desc; |
131 | unsigned npins; |
132 | }; |
133 | |
134 | static const struct pinconf_generic_params pm8xxx_mpp_bindings[] = { |
135 | {"qcom,amux-route" , PM8XXX_CONFIG_AMUX, 0}, |
136 | {"qcom,analog-level" , PM8XXX_CONFIG_ALEVEL, 0}, |
137 | {"qcom,dtest" , PM8XXX_CONFIG_DTEST_SELECTOR, 0}, |
138 | {"qcom,paired" , PM8XXX_CONFIG_PAIRED, 0}, |
139 | }; |
140 | |
141 | #ifdef CONFIG_DEBUG_FS |
142 | static const struct pin_config_item pm8xxx_conf_items[] = { |
143 | PCONFDUMP(PM8XXX_CONFIG_AMUX, "analog mux" , NULL, true), |
144 | PCONFDUMP(PM8XXX_CONFIG_ALEVEL, "analog level" , NULL, true), |
145 | PCONFDUMP(PM8XXX_CONFIG_DTEST_SELECTOR, "dtest" , NULL, true), |
146 | PCONFDUMP(PM8XXX_CONFIG_PAIRED, "paired" , NULL, false), |
147 | }; |
148 | #endif |
149 | |
150 | #define PM8XXX_MAX_MPPS 12 |
151 | #define PM8XXX_MPP_PHYSICAL_OFFSET 1 |
152 | |
153 | static const char * const pm8xxx_groups[PM8XXX_MAX_MPPS] = { |
154 | "mpp1" , "mpp2" , "mpp3" , "mpp4" , "mpp5" , "mpp6" , "mpp7" , "mpp8" , |
155 | "mpp9" , "mpp10" , "mpp11" , "mpp12" , |
156 | }; |
157 | |
158 | #define PM8XXX_MPP_DIGITAL 0 |
159 | #define PM8XXX_MPP_ANALOG 1 |
160 | #define PM8XXX_MPP_SINK 2 |
161 | |
162 | static const char * const pm8xxx_mpp_functions[] = { |
163 | "digital" , "analog" , "sink" , |
164 | }; |
165 | |
166 | static int pm8xxx_mpp_update(struct pm8xxx_mpp *pctrl, |
167 | struct pm8xxx_pin_data *pin) |
168 | { |
169 | unsigned level; |
170 | unsigned ctrl; |
171 | unsigned type; |
172 | int ret; |
173 | u8 val; |
174 | |
175 | switch (pin->mode) { |
176 | case PM8XXX_MPP_DIGITAL: |
177 | if (pin->dtest) { |
178 | type = PM8XXX_MPP_TYPE_DTEST_OUTPUT; |
179 | ctrl = pin->dtest - 1; |
180 | } else if (pin->input && pin->output) { |
181 | type = PM8XXX_MPP_TYPE_D_BI_DIR; |
182 | if (pin->high_z) |
183 | ctrl = PM8XXX_MPP_BI_PULLUP_OPEN; |
184 | else if (pin->pullup == 600) |
185 | ctrl = PM8XXX_MPP_BI_PULLUP_1KOHM; |
186 | else if (pin->pullup == 10000) |
187 | ctrl = PM8XXX_MPP_BI_PULLUP_10KOHM; |
188 | else |
189 | ctrl = PM8XXX_MPP_BI_PULLUP_30KOHM; |
190 | } else if (pin->input) { |
191 | type = PM8XXX_MPP_TYPE_D_INPUT; |
192 | if (pin->dtest) |
193 | ctrl = pin->dtest; |
194 | else |
195 | ctrl = PM8XXX_MPP_DIN_TO_INT; |
196 | } else { |
197 | type = PM8XXX_MPP_TYPE_D_OUTPUT; |
198 | ctrl = !!pin->output_value; |
199 | if (pin->paired) |
200 | ctrl |= BIT(1); |
201 | } |
202 | |
203 | level = pin->power_source; |
204 | break; |
205 | case PM8XXX_MPP_ANALOG: |
206 | if (pin->output) { |
207 | type = PM8XXX_MPP_TYPE_A_OUTPUT; |
208 | level = pin->aout_level; |
209 | ctrl = pin->output_value; |
210 | if (pin->paired) |
211 | ctrl |= BIT(1); |
212 | } else { |
213 | type = PM8XXX_MPP_TYPE_A_INPUT; |
214 | level = pin->amux; |
215 | ctrl = 0; |
216 | } |
217 | break; |
218 | case PM8XXX_MPP_SINK: |
219 | level = (pin->drive_strength / 5) - 1; |
220 | if (pin->dtest) { |
221 | type = PM8XXX_MPP_TYPE_DTEST_SINK; |
222 | ctrl = pin->dtest - 1; |
223 | } else { |
224 | type = PM8XXX_MPP_TYPE_SINK; |
225 | ctrl = pin->output_value; |
226 | if (pin->paired) |
227 | ctrl |= BIT(1); |
228 | } |
229 | break; |
230 | default: |
231 | return -EINVAL; |
232 | } |
233 | |
234 | val = type << 5 | level << 2 | ctrl; |
235 | ret = regmap_write(map: pctrl->regmap, reg: pin->reg, val); |
236 | if (ret) |
237 | dev_err(pctrl->dev, "failed to write register\n" ); |
238 | |
239 | return ret; |
240 | } |
241 | |
242 | static int pm8xxx_get_groups_count(struct pinctrl_dev *pctldev) |
243 | { |
244 | struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); |
245 | |
246 | return pctrl->npins; |
247 | } |
248 | |
249 | static const char *pm8xxx_get_group_name(struct pinctrl_dev *pctldev, |
250 | unsigned group) |
251 | { |
252 | return pm8xxx_groups[group]; |
253 | } |
254 | |
255 | |
256 | static int pm8xxx_get_group_pins(struct pinctrl_dev *pctldev, |
257 | unsigned group, |
258 | const unsigned **pins, |
259 | unsigned *num_pins) |
260 | { |
261 | struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); |
262 | |
263 | *pins = &pctrl->desc.pins[group].number; |
264 | *num_pins = 1; |
265 | |
266 | return 0; |
267 | } |
268 | |
269 | static const struct pinctrl_ops pm8xxx_pinctrl_ops = { |
270 | .get_groups_count = pm8xxx_get_groups_count, |
271 | .get_group_name = pm8xxx_get_group_name, |
272 | .get_group_pins = pm8xxx_get_group_pins, |
273 | .dt_node_to_map = pinconf_generic_dt_node_to_map_group, |
274 | .dt_free_map = pinctrl_utils_free_map, |
275 | }; |
276 | |
277 | static int pm8xxx_get_functions_count(struct pinctrl_dev *pctldev) |
278 | { |
279 | return ARRAY_SIZE(pm8xxx_mpp_functions); |
280 | } |
281 | |
282 | static const char *pm8xxx_get_function_name(struct pinctrl_dev *pctldev, |
283 | unsigned function) |
284 | { |
285 | return pm8xxx_mpp_functions[function]; |
286 | } |
287 | |
288 | static int pm8xxx_get_function_groups(struct pinctrl_dev *pctldev, |
289 | unsigned function, |
290 | const char * const **groups, |
291 | unsigned * const num_groups) |
292 | { |
293 | struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); |
294 | |
295 | *groups = pm8xxx_groups; |
296 | *num_groups = pctrl->npins; |
297 | return 0; |
298 | } |
299 | |
300 | static int pm8xxx_pinmux_set_mux(struct pinctrl_dev *pctldev, |
301 | unsigned function, |
302 | unsigned group) |
303 | { |
304 | struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); |
305 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[group].drv_data; |
306 | |
307 | pin->mode = function; |
308 | pm8xxx_mpp_update(pctrl, pin); |
309 | |
310 | return 0; |
311 | } |
312 | |
313 | static const struct pinmux_ops pm8xxx_pinmux_ops = { |
314 | .get_functions_count = pm8xxx_get_functions_count, |
315 | .get_function_name = pm8xxx_get_function_name, |
316 | .get_function_groups = pm8xxx_get_function_groups, |
317 | .set_mux = pm8xxx_pinmux_set_mux, |
318 | }; |
319 | |
320 | static int pm8xxx_pin_config_get(struct pinctrl_dev *pctldev, |
321 | unsigned int offset, |
322 | unsigned long *config) |
323 | { |
324 | struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); |
325 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; |
326 | unsigned param = pinconf_to_config_param(config: *config); |
327 | unsigned arg; |
328 | |
329 | switch (param) { |
330 | case PIN_CONFIG_BIAS_PULL_UP: |
331 | arg = pin->pullup; |
332 | break; |
333 | case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: |
334 | arg = pin->high_z; |
335 | break; |
336 | case PIN_CONFIG_INPUT_ENABLE: |
337 | arg = pin->input; |
338 | break; |
339 | case PIN_CONFIG_OUTPUT: |
340 | arg = pin->output_value; |
341 | break; |
342 | case PIN_CONFIG_POWER_SOURCE: |
343 | arg = pin->power_source; |
344 | break; |
345 | case PIN_CONFIG_DRIVE_STRENGTH: |
346 | arg = pin->drive_strength; |
347 | break; |
348 | case PM8XXX_CONFIG_DTEST_SELECTOR: |
349 | arg = pin->dtest; |
350 | break; |
351 | case PM8XXX_CONFIG_AMUX: |
352 | arg = pin->amux; |
353 | break; |
354 | case PM8XXX_CONFIG_ALEVEL: |
355 | arg = pin->aout_level; |
356 | break; |
357 | case PM8XXX_CONFIG_PAIRED: |
358 | arg = pin->paired; |
359 | break; |
360 | default: |
361 | return -EINVAL; |
362 | } |
363 | |
364 | *config = pinconf_to_config_packed(param, argument: arg); |
365 | |
366 | return 0; |
367 | } |
368 | |
369 | static int pm8xxx_pin_config_set(struct pinctrl_dev *pctldev, |
370 | unsigned int offset, |
371 | unsigned long *configs, |
372 | unsigned num_configs) |
373 | { |
374 | struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); |
375 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; |
376 | unsigned param; |
377 | unsigned arg; |
378 | unsigned i; |
379 | |
380 | for (i = 0; i < num_configs; i++) { |
381 | param = pinconf_to_config_param(config: configs[i]); |
382 | arg = pinconf_to_config_argument(config: configs[i]); |
383 | |
384 | switch (param) { |
385 | case PIN_CONFIG_BIAS_PULL_UP: |
386 | pin->pullup = arg; |
387 | break; |
388 | case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: |
389 | pin->high_z = true; |
390 | break; |
391 | case PIN_CONFIG_INPUT_ENABLE: |
392 | pin->input = true; |
393 | break; |
394 | case PIN_CONFIG_OUTPUT: |
395 | pin->output = true; |
396 | pin->output_value = !!arg; |
397 | break; |
398 | case PIN_CONFIG_POWER_SOURCE: |
399 | pin->power_source = arg; |
400 | break; |
401 | case PIN_CONFIG_DRIVE_STRENGTH: |
402 | pin->drive_strength = arg; |
403 | break; |
404 | case PM8XXX_CONFIG_DTEST_SELECTOR: |
405 | pin->dtest = arg; |
406 | break; |
407 | case PM8XXX_CONFIG_AMUX: |
408 | pin->amux = arg; |
409 | break; |
410 | case PM8XXX_CONFIG_ALEVEL: |
411 | pin->aout_level = arg; |
412 | break; |
413 | case PM8XXX_CONFIG_PAIRED: |
414 | pin->paired = !!arg; |
415 | break; |
416 | default: |
417 | dev_err(pctrl->dev, |
418 | "unsupported config parameter: %x\n" , |
419 | param); |
420 | return -EINVAL; |
421 | } |
422 | } |
423 | |
424 | pm8xxx_mpp_update(pctrl, pin); |
425 | |
426 | return 0; |
427 | } |
428 | |
429 | static const struct pinconf_ops pm8xxx_pinconf_ops = { |
430 | .is_generic = true, |
431 | .pin_config_group_get = pm8xxx_pin_config_get, |
432 | .pin_config_group_set = pm8xxx_pin_config_set, |
433 | }; |
434 | |
435 | static const struct pinctrl_desc pm8xxx_pinctrl_desc = { |
436 | .name = "pm8xxx_mpp" , |
437 | .pctlops = &pm8xxx_pinctrl_ops, |
438 | .pmxops = &pm8xxx_pinmux_ops, |
439 | .confops = &pm8xxx_pinconf_ops, |
440 | .owner = THIS_MODULE, |
441 | }; |
442 | |
443 | static int pm8xxx_mpp_direction_input(struct gpio_chip *chip, |
444 | unsigned offset) |
445 | { |
446 | struct pm8xxx_mpp *pctrl = gpiochip_get_data(gc: chip); |
447 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; |
448 | |
449 | switch (pin->mode) { |
450 | case PM8XXX_MPP_DIGITAL: |
451 | pin->input = true; |
452 | break; |
453 | case PM8XXX_MPP_ANALOG: |
454 | pin->input = true; |
455 | pin->output = true; |
456 | break; |
457 | case PM8XXX_MPP_SINK: |
458 | return -EINVAL; |
459 | } |
460 | |
461 | pm8xxx_mpp_update(pctrl, pin); |
462 | |
463 | return 0; |
464 | } |
465 | |
466 | static int pm8xxx_mpp_direction_output(struct gpio_chip *chip, |
467 | unsigned offset, |
468 | int value) |
469 | { |
470 | struct pm8xxx_mpp *pctrl = gpiochip_get_data(gc: chip); |
471 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; |
472 | |
473 | switch (pin->mode) { |
474 | case PM8XXX_MPP_DIGITAL: |
475 | pin->output = true; |
476 | break; |
477 | case PM8XXX_MPP_ANALOG: |
478 | pin->input = false; |
479 | pin->output = true; |
480 | break; |
481 | case PM8XXX_MPP_SINK: |
482 | pin->input = false; |
483 | pin->output = true; |
484 | break; |
485 | } |
486 | |
487 | pm8xxx_mpp_update(pctrl, pin); |
488 | |
489 | return 0; |
490 | } |
491 | |
492 | static int pm8xxx_mpp_get(struct gpio_chip *chip, unsigned offset) |
493 | { |
494 | struct pm8xxx_mpp *pctrl = gpiochip_get_data(gc: chip); |
495 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; |
496 | bool state; |
497 | int ret, irq; |
498 | |
499 | if (!pin->input) |
500 | return !!pin->output_value; |
501 | |
502 | irq = chip->to_irq(chip, offset); |
503 | if (irq < 0) |
504 | return irq; |
505 | |
506 | ret = irq_get_irqchip_state(irq, which: IRQCHIP_STATE_LINE_LEVEL, state: &state); |
507 | if (!ret) |
508 | ret = !!state; |
509 | |
510 | return ret; |
511 | } |
512 | |
513 | static void pm8xxx_mpp_set(struct gpio_chip *chip, unsigned offset, int value) |
514 | { |
515 | struct pm8xxx_mpp *pctrl = gpiochip_get_data(gc: chip); |
516 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; |
517 | |
518 | pin->output_value = !!value; |
519 | |
520 | pm8xxx_mpp_update(pctrl, pin); |
521 | } |
522 | |
523 | static int pm8xxx_mpp_of_xlate(struct gpio_chip *chip, |
524 | const struct of_phandle_args *gpio_desc, |
525 | u32 *flags) |
526 | { |
527 | if (chip->of_gpio_n_cells < 2) |
528 | return -EINVAL; |
529 | |
530 | if (flags) |
531 | *flags = gpio_desc->args[1]; |
532 | |
533 | return gpio_desc->args[0] - PM8XXX_MPP_PHYSICAL_OFFSET; |
534 | } |
535 | |
536 | |
537 | #ifdef CONFIG_DEBUG_FS |
538 | |
539 | static void pm8xxx_mpp_dbg_show_one(struct seq_file *s, |
540 | struct pinctrl_dev *pctldev, |
541 | struct gpio_chip *chip, |
542 | unsigned offset, |
543 | unsigned gpio) |
544 | { |
545 | struct pm8xxx_mpp *pctrl = gpiochip_get_data(gc: chip); |
546 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; |
547 | |
548 | static const char * const aout_lvls[] = { |
549 | "1v25" , "1v25_2" , "0v625" , "0v3125" , "mpp" , "abus1" , "abus2" , |
550 | "abus3" |
551 | }; |
552 | |
553 | static const char * const amuxs[] = { |
554 | "amux5" , "amux6" , "amux7" , "amux8" , "amux9" , "abus1" , "abus2" , |
555 | "abus3" , |
556 | }; |
557 | |
558 | seq_printf(m: s, fmt: " mpp%-2d:" , offset + PM8XXX_MPP_PHYSICAL_OFFSET); |
559 | |
560 | switch (pin->mode) { |
561 | case PM8XXX_MPP_DIGITAL: |
562 | seq_puts(m: s, s: " digital " ); |
563 | if (pin->dtest) { |
564 | seq_printf(m: s, fmt: "dtest%d\n" , pin->dtest); |
565 | } else if (pin->input && pin->output) { |
566 | if (pin->high_z) |
567 | seq_puts(m: s, s: "bi-dir high-z" ); |
568 | else |
569 | seq_printf(m: s, fmt: "bi-dir %dOhm" , pin->pullup); |
570 | } else if (pin->input) { |
571 | if (pin->dtest) |
572 | seq_printf(m: s, fmt: "in dtest%d" , pin->dtest); |
573 | else |
574 | seq_puts(m: s, s: "in gpio" ); |
575 | } else if (pin->output) { |
576 | seq_puts(m: s, s: "out " ); |
577 | |
578 | if (!pin->paired) { |
579 | seq_puts(m: s, s: pin->output_value ? |
580 | "high" : "low" ); |
581 | } else { |
582 | seq_puts(m: s, s: pin->output_value ? |
583 | "inverted" : "follow" ); |
584 | } |
585 | } |
586 | break; |
587 | case PM8XXX_MPP_ANALOG: |
588 | seq_puts(m: s, s: " analog " ); |
589 | if (pin->output) { |
590 | seq_printf(m: s, fmt: "out %s " , aout_lvls[pin->aout_level]); |
591 | if (!pin->paired) { |
592 | seq_puts(m: s, s: pin->output_value ? |
593 | "high" : "low" ); |
594 | } else { |
595 | seq_puts(m: s, s: pin->output_value ? |
596 | "inverted" : "follow" ); |
597 | } |
598 | } else { |
599 | seq_printf(m: s, fmt: "input mux %s" , amuxs[pin->amux]); |
600 | } |
601 | break; |
602 | case PM8XXX_MPP_SINK: |
603 | seq_printf(m: s, fmt: " sink %dmA " , pin->drive_strength); |
604 | if (pin->dtest) { |
605 | seq_printf(m: s, fmt: "dtest%d" , pin->dtest); |
606 | } else { |
607 | if (!pin->paired) { |
608 | seq_puts(m: s, s: pin->output_value ? |
609 | "high" : "low" ); |
610 | } else { |
611 | seq_puts(m: s, s: pin->output_value ? |
612 | "inverted" : "follow" ); |
613 | } |
614 | } |
615 | break; |
616 | } |
617 | } |
618 | |
619 | static void pm8xxx_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip) |
620 | { |
621 | unsigned gpio = chip->base; |
622 | unsigned i; |
623 | |
624 | for (i = 0; i < chip->ngpio; i++, gpio++) { |
625 | pm8xxx_mpp_dbg_show_one(s, NULL, chip, offset: i, gpio); |
626 | seq_puts(m: s, s: "\n" ); |
627 | } |
628 | } |
629 | |
630 | #else |
631 | #define pm8xxx_mpp_dbg_show NULL |
632 | #endif |
633 | |
634 | static const struct gpio_chip pm8xxx_mpp_template = { |
635 | .direction_input = pm8xxx_mpp_direction_input, |
636 | .direction_output = pm8xxx_mpp_direction_output, |
637 | .get = pm8xxx_mpp_get, |
638 | .set = pm8xxx_mpp_set, |
639 | .of_xlate = pm8xxx_mpp_of_xlate, |
640 | .dbg_show = pm8xxx_mpp_dbg_show, |
641 | .owner = THIS_MODULE, |
642 | }; |
643 | |
644 | static int pm8xxx_pin_populate(struct pm8xxx_mpp *pctrl, |
645 | struct pm8xxx_pin_data *pin) |
646 | { |
647 | unsigned int val; |
648 | unsigned level; |
649 | unsigned ctrl; |
650 | unsigned type; |
651 | int ret; |
652 | |
653 | ret = regmap_read(map: pctrl->regmap, reg: pin->reg, val: &val); |
654 | if (ret) { |
655 | dev_err(pctrl->dev, "failed to read register\n" ); |
656 | return ret; |
657 | } |
658 | |
659 | type = (val >> 5) & 7; |
660 | level = (val >> 2) & 7; |
661 | ctrl = (val) & 3; |
662 | |
663 | switch (type) { |
664 | case PM8XXX_MPP_TYPE_D_INPUT: |
665 | pin->mode = PM8XXX_MPP_DIGITAL; |
666 | pin->input = true; |
667 | pin->power_source = level; |
668 | pin->dtest = ctrl; |
669 | break; |
670 | case PM8XXX_MPP_TYPE_D_OUTPUT: |
671 | pin->mode = PM8XXX_MPP_DIGITAL; |
672 | pin->output = true; |
673 | pin->power_source = level; |
674 | pin->output_value = !!(ctrl & BIT(0)); |
675 | pin->paired = !!(ctrl & BIT(1)); |
676 | break; |
677 | case PM8XXX_MPP_TYPE_D_BI_DIR: |
678 | pin->mode = PM8XXX_MPP_DIGITAL; |
679 | pin->input = true; |
680 | pin->output = true; |
681 | pin->power_source = level; |
682 | switch (ctrl) { |
683 | case PM8XXX_MPP_BI_PULLUP_1KOHM: |
684 | pin->pullup = 600; |
685 | break; |
686 | case PM8XXX_MPP_BI_PULLUP_OPEN: |
687 | pin->high_z = true; |
688 | break; |
689 | case PM8XXX_MPP_BI_PULLUP_10KOHM: |
690 | pin->pullup = 10000; |
691 | break; |
692 | case PM8XXX_MPP_BI_PULLUP_30KOHM: |
693 | pin->pullup = 30000; |
694 | break; |
695 | } |
696 | break; |
697 | case PM8XXX_MPP_TYPE_A_INPUT: |
698 | pin->mode = PM8XXX_MPP_ANALOG; |
699 | pin->input = true; |
700 | pin->amux = level; |
701 | break; |
702 | case PM8XXX_MPP_TYPE_A_OUTPUT: |
703 | pin->mode = PM8XXX_MPP_ANALOG; |
704 | pin->output = true; |
705 | pin->aout_level = level; |
706 | pin->output_value = !!(ctrl & BIT(0)); |
707 | pin->paired = !!(ctrl & BIT(1)); |
708 | break; |
709 | case PM8XXX_MPP_TYPE_SINK: |
710 | pin->mode = PM8XXX_MPP_SINK; |
711 | pin->drive_strength = 5 * (level + 1); |
712 | pin->output_value = !!(ctrl & BIT(0)); |
713 | pin->paired = !!(ctrl & BIT(1)); |
714 | break; |
715 | case PM8XXX_MPP_TYPE_DTEST_SINK: |
716 | pin->mode = PM8XXX_MPP_SINK; |
717 | pin->dtest = ctrl + 1; |
718 | pin->drive_strength = 5 * (level + 1); |
719 | break; |
720 | case PM8XXX_MPP_TYPE_DTEST_OUTPUT: |
721 | pin->mode = PM8XXX_MPP_DIGITAL; |
722 | pin->power_source = level; |
723 | if (ctrl >= 1) |
724 | pin->dtest = ctrl; |
725 | break; |
726 | } |
727 | |
728 | return 0; |
729 | } |
730 | |
731 | static int pm8xxx_mpp_domain_translate(struct irq_domain *domain, |
732 | struct irq_fwspec *fwspec, |
733 | unsigned long *hwirq, |
734 | unsigned int *type) |
735 | { |
736 | struct pm8xxx_mpp *pctrl = container_of(domain->host_data, |
737 | struct pm8xxx_mpp, chip); |
738 | |
739 | if (fwspec->param_count != 2 || |
740 | fwspec->param[0] < PM8XXX_MPP_PHYSICAL_OFFSET || |
741 | fwspec->param[0] > pctrl->chip.ngpio) |
742 | return -EINVAL; |
743 | |
744 | *hwirq = fwspec->param[0] - PM8XXX_MPP_PHYSICAL_OFFSET; |
745 | *type = fwspec->param[1]; |
746 | |
747 | return 0; |
748 | } |
749 | |
750 | static unsigned int pm8xxx_mpp_child_offset_to_irq(struct gpio_chip *chip, |
751 | unsigned int offset) |
752 | { |
753 | return offset + PM8XXX_MPP_PHYSICAL_OFFSET; |
754 | } |
755 | |
756 | static int pm8821_mpp_child_to_parent_hwirq(struct gpio_chip *chip, |
757 | unsigned int child_hwirq, |
758 | unsigned int child_type, |
759 | unsigned int *parent_hwirq, |
760 | unsigned int *parent_type) |
761 | { |
762 | *parent_hwirq = child_hwirq + 24; |
763 | *parent_type = child_type; |
764 | |
765 | return 0; |
766 | } |
767 | |
768 | static int pm8xxx_mpp_child_to_parent_hwirq(struct gpio_chip *chip, |
769 | unsigned int child_hwirq, |
770 | unsigned int child_type, |
771 | unsigned int *parent_hwirq, |
772 | unsigned int *parent_type) |
773 | { |
774 | *parent_hwirq = child_hwirq + 0x80; |
775 | *parent_type = child_type; |
776 | |
777 | return 0; |
778 | } |
779 | |
780 | static void pm8xxx_mpp_irq_disable(struct irq_data *d) |
781 | { |
782 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
783 | |
784 | gpiochip_disable_irq(gc, offset: irqd_to_hwirq(d)); |
785 | } |
786 | |
787 | static void pm8xxx_mpp_irq_enable(struct irq_data *d) |
788 | { |
789 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
790 | |
791 | gpiochip_enable_irq(gc, offset: irqd_to_hwirq(d)); |
792 | } |
793 | |
794 | static const struct irq_chip pm8xxx_mpp_irq_chip = { |
795 | .name = "ssbi-mpp" , |
796 | .irq_mask_ack = irq_chip_mask_ack_parent, |
797 | .irq_unmask = irq_chip_unmask_parent, |
798 | .irq_disable = pm8xxx_mpp_irq_disable, |
799 | .irq_enable = pm8xxx_mpp_irq_enable, |
800 | .irq_set_type = irq_chip_set_type_parent, |
801 | .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE | |
802 | IRQCHIP_IMMUTABLE, |
803 | GPIOCHIP_IRQ_RESOURCE_HELPERS, |
804 | }; |
805 | |
806 | static const struct of_device_id pm8xxx_mpp_of_match[] = { |
807 | { .compatible = "qcom,pm8018-mpp" , .data = (void *) 6 }, |
808 | { .compatible = "qcom,pm8038-mpp" , .data = (void *) 6 }, |
809 | { .compatible = "qcom,pm8058-mpp" , .data = (void *) 12 }, |
810 | { .compatible = "qcom,pm8821-mpp" , .data = (void *) 4 }, |
811 | { .compatible = "qcom,pm8917-mpp" , .data = (void *) 10 }, |
812 | { .compatible = "qcom,pm8921-mpp" , .data = (void *) 12 }, |
813 | { }, |
814 | }; |
815 | MODULE_DEVICE_TABLE(of, pm8xxx_mpp_of_match); |
816 | |
817 | static int pm8xxx_mpp_probe(struct platform_device *pdev) |
818 | { |
819 | struct pm8xxx_pin_data *pin_data; |
820 | struct irq_domain *parent_domain; |
821 | struct device_node *parent_node; |
822 | struct pinctrl_pin_desc *pins; |
823 | struct gpio_irq_chip *girq; |
824 | struct pm8xxx_mpp *pctrl; |
825 | int ret; |
826 | int i; |
827 | |
828 | pctrl = devm_kzalloc(dev: &pdev->dev, size: sizeof(*pctrl), GFP_KERNEL); |
829 | if (!pctrl) |
830 | return -ENOMEM; |
831 | |
832 | pctrl->dev = &pdev->dev; |
833 | pctrl->npins = (uintptr_t) device_get_match_data(dev: &pdev->dev); |
834 | |
835 | pctrl->regmap = dev_get_regmap(dev: pdev->dev.parent, NULL); |
836 | if (!pctrl->regmap) { |
837 | dev_err(&pdev->dev, "parent regmap unavailable\n" ); |
838 | return -ENXIO; |
839 | } |
840 | |
841 | pctrl->desc = pm8xxx_pinctrl_desc; |
842 | pctrl->desc.npins = pctrl->npins; |
843 | |
844 | pins = devm_kcalloc(dev: &pdev->dev, |
845 | n: pctrl->desc.npins, |
846 | size: sizeof(struct pinctrl_pin_desc), |
847 | GFP_KERNEL); |
848 | if (!pins) |
849 | return -ENOMEM; |
850 | |
851 | pin_data = devm_kcalloc(dev: &pdev->dev, |
852 | n: pctrl->desc.npins, |
853 | size: sizeof(struct pm8xxx_pin_data), |
854 | GFP_KERNEL); |
855 | if (!pin_data) |
856 | return -ENOMEM; |
857 | |
858 | for (i = 0; i < pctrl->desc.npins; i++) { |
859 | pin_data[i].reg = SSBI_REG_ADDR_MPP(i); |
860 | |
861 | ret = pm8xxx_pin_populate(pctrl, pin: &pin_data[i]); |
862 | if (ret) |
863 | return ret; |
864 | |
865 | pins[i].number = i; |
866 | pins[i].name = pm8xxx_groups[i]; |
867 | pins[i].drv_data = &pin_data[i]; |
868 | } |
869 | pctrl->desc.pins = pins; |
870 | |
871 | pctrl->desc.num_custom_params = ARRAY_SIZE(pm8xxx_mpp_bindings); |
872 | pctrl->desc.custom_params = pm8xxx_mpp_bindings; |
873 | #ifdef CONFIG_DEBUG_FS |
874 | pctrl->desc.custom_conf_items = pm8xxx_conf_items; |
875 | #endif |
876 | |
877 | pctrl->pctrl = devm_pinctrl_register(dev: &pdev->dev, pctldesc: &pctrl->desc, driver_data: pctrl); |
878 | if (IS_ERR(ptr: pctrl->pctrl)) { |
879 | dev_err(&pdev->dev, "couldn't register pm8xxx mpp driver\n" ); |
880 | return PTR_ERR(ptr: pctrl->pctrl); |
881 | } |
882 | |
883 | pctrl->chip = pm8xxx_mpp_template; |
884 | pctrl->chip.base = -1; |
885 | pctrl->chip.parent = &pdev->dev; |
886 | pctrl->chip.of_gpio_n_cells = 2; |
887 | pctrl->chip.label = dev_name(dev: pctrl->dev); |
888 | pctrl->chip.ngpio = pctrl->npins; |
889 | |
890 | parent_node = of_irq_find_parent(child: pctrl->dev->of_node); |
891 | if (!parent_node) |
892 | return -ENXIO; |
893 | |
894 | parent_domain = irq_find_host(node: parent_node); |
895 | of_node_put(node: parent_node); |
896 | if (!parent_domain) |
897 | return -ENXIO; |
898 | |
899 | girq = &pctrl->chip.irq; |
900 | gpio_irq_chip_set_chip(girq, chip: &pm8xxx_mpp_irq_chip); |
901 | girq->default_type = IRQ_TYPE_NONE; |
902 | girq->handler = handle_level_irq; |
903 | girq->fwnode = dev_fwnode(pctrl->dev); |
904 | girq->parent_domain = parent_domain; |
905 | if (of_device_is_compatible(device: pdev->dev.of_node, "qcom,pm8821-mpp" )) |
906 | girq->child_to_parent_hwirq = pm8821_mpp_child_to_parent_hwirq; |
907 | else |
908 | girq->child_to_parent_hwirq = pm8xxx_mpp_child_to_parent_hwirq; |
909 | girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_twocell; |
910 | girq->child_offset_to_irq = pm8xxx_mpp_child_offset_to_irq; |
911 | girq->child_irq_domain_ops.translate = pm8xxx_mpp_domain_translate; |
912 | |
913 | ret = gpiochip_add_data(&pctrl->chip, pctrl); |
914 | if (ret) { |
915 | dev_err(&pdev->dev, "failed register gpiochip\n" ); |
916 | return ret; |
917 | } |
918 | |
919 | ret = gpiochip_add_pin_range(gc: &pctrl->chip, |
920 | pinctl_name: dev_name(dev: pctrl->dev), |
921 | gpio_offset: 0, pin_offset: 0, npins: pctrl->chip.ngpio); |
922 | if (ret) { |
923 | dev_err(pctrl->dev, "failed to add pin range\n" ); |
924 | goto unregister_gpiochip; |
925 | } |
926 | |
927 | platform_set_drvdata(pdev, data: pctrl); |
928 | |
929 | dev_dbg(&pdev->dev, "Qualcomm pm8xxx mpp driver probed\n" ); |
930 | |
931 | return 0; |
932 | |
933 | unregister_gpiochip: |
934 | gpiochip_remove(gc: &pctrl->chip); |
935 | |
936 | return ret; |
937 | } |
938 | |
939 | static void pm8xxx_mpp_remove(struct platform_device *pdev) |
940 | { |
941 | struct pm8xxx_mpp *pctrl = platform_get_drvdata(pdev); |
942 | |
943 | gpiochip_remove(gc: &pctrl->chip); |
944 | } |
945 | |
946 | static struct platform_driver pm8xxx_mpp_driver = { |
947 | .driver = { |
948 | .name = "qcom-ssbi-mpp" , |
949 | .of_match_table = pm8xxx_mpp_of_match, |
950 | }, |
951 | .probe = pm8xxx_mpp_probe, |
952 | .remove_new = pm8xxx_mpp_remove, |
953 | }; |
954 | |
955 | module_platform_driver(pm8xxx_mpp_driver); |
956 | |
957 | MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>" ); |
958 | MODULE_DESCRIPTION("Qualcomm PM8xxx MPP driver" ); |
959 | MODULE_LICENSE("GPL v2" ); |
960 | |