1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. |
4 | */ |
5 | |
6 | #include <linux/gpio/driver.h> |
7 | #include <linux/module.h> |
8 | #include <linux/of.h> |
9 | #include <linux/of_irq.h> |
10 | #include <linux/platform_device.h> |
11 | #include <linux/regmap.h> |
12 | #include <linux/seq_file.h> |
13 | #include <linux/slab.h> |
14 | #include <linux/types.h> |
15 | |
16 | #include <linux/pinctrl/pinconf-generic.h> |
17 | #include <linux/pinctrl/pinconf.h> |
18 | #include <linux/pinctrl/pinmux.h> |
19 | |
20 | #include <dt-bindings/pinctrl/qcom,pmic-mpp.h> |
21 | |
22 | #include "../core.h" |
23 | #include "../pinctrl-utils.h" |
24 | |
25 | #define PMIC_MPP_ADDRESS_RANGE 0x100 |
26 | |
27 | /* |
28 | * Pull Up Values - it indicates whether a pull-up should be |
29 | * applied for bidirectional mode only. The hardware ignores the |
30 | * configuration when operating in other modes. |
31 | */ |
32 | #define PMIC_MPP_PULL_UP_0P6KOHM 0 |
33 | #define PMIC_MPP_PULL_UP_10KOHM 1 |
34 | #define PMIC_MPP_PULL_UP_30KOHM 2 |
35 | #define PMIC_MPP_PULL_UP_OPEN 3 |
36 | |
37 | /* type registers base address bases */ |
38 | #define PMIC_MPP_REG_TYPE 0x4 |
39 | #define PMIC_MPP_REG_SUBTYPE 0x5 |
40 | |
41 | /* mpp peripheral type and subtype values */ |
42 | #define PMIC_MPP_TYPE 0x11 |
43 | #define PMIC_MPP_SUBTYPE_4CH_NO_ANA_OUT 0x3 |
44 | #define PMIC_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT 0x4 |
45 | #define PMIC_MPP_SUBTYPE_4CH_NO_SINK 0x5 |
46 | #define PMIC_MPP_SUBTYPE_ULT_4CH_NO_SINK 0x6 |
47 | #define PMIC_MPP_SUBTYPE_4CH_FULL_FUNC 0x7 |
48 | #define PMIC_MPP_SUBTYPE_8CH_FULL_FUNC 0xf |
49 | |
50 | #define PMIC_MPP_REG_RT_STS 0x10 |
51 | #define PMIC_MPP_REG_RT_STS_VAL_MASK 0x1 |
52 | |
53 | /* control register base address bases */ |
54 | #define PMIC_MPP_REG_MODE_CTL 0x40 |
55 | #define PMIC_MPP_REG_DIG_VIN_CTL 0x41 |
56 | #define PMIC_MPP_REG_DIG_PULL_CTL 0x42 |
57 | #define PMIC_MPP_REG_DIG_IN_CTL 0x43 |
58 | #define PMIC_MPP_REG_EN_CTL 0x46 |
59 | #define PMIC_MPP_REG_AOUT_CTL 0x48 |
60 | #define PMIC_MPP_REG_AIN_CTL 0x4a |
61 | #define PMIC_MPP_REG_SINK_CTL 0x4c |
62 | |
63 | /* PMIC_MPP_REG_MODE_CTL */ |
64 | #define PMIC_MPP_REG_MODE_VALUE_MASK 0x1 |
65 | #define PMIC_MPP_REG_MODE_FUNCTION_SHIFT 1 |
66 | #define PMIC_MPP_REG_MODE_FUNCTION_MASK 0x7 |
67 | #define PMIC_MPP_REG_MODE_DIR_SHIFT 4 |
68 | #define PMIC_MPP_REG_MODE_DIR_MASK 0x7 |
69 | |
70 | /* PMIC_MPP_REG_DIG_VIN_CTL */ |
71 | #define PMIC_MPP_REG_VIN_SHIFT 0 |
72 | #define PMIC_MPP_REG_VIN_MASK 0x7 |
73 | |
74 | /* PMIC_MPP_REG_DIG_PULL_CTL */ |
75 | #define PMIC_MPP_REG_PULL_SHIFT 0 |
76 | #define PMIC_MPP_REG_PULL_MASK 0x7 |
77 | |
78 | /* PMIC_MPP_REG_EN_CTL */ |
79 | #define PMIC_MPP_REG_MASTER_EN_SHIFT 7 |
80 | |
81 | /* PMIC_MPP_REG_AIN_CTL */ |
82 | #define PMIC_MPP_REG_AIN_ROUTE_SHIFT 0 |
83 | #define PMIC_MPP_REG_AIN_ROUTE_MASK 0x7 |
84 | |
85 | #define PMIC_MPP_MODE_DIGITAL_INPUT 0 |
86 | #define PMIC_MPP_MODE_DIGITAL_OUTPUT 1 |
87 | #define PMIC_MPP_MODE_DIGITAL_BIDIR 2 |
88 | #define PMIC_MPP_MODE_ANALOG_BIDIR 3 |
89 | #define PMIC_MPP_MODE_ANALOG_INPUT 4 |
90 | #define PMIC_MPP_MODE_ANALOG_OUTPUT 5 |
91 | #define PMIC_MPP_MODE_CURRENT_SINK 6 |
92 | |
93 | #define PMIC_MPP_SELECTOR_NORMAL 0 |
94 | #define PMIC_MPP_SELECTOR_PAIRED 1 |
95 | #define PMIC_MPP_SELECTOR_DTEST_FIRST 4 |
96 | |
97 | #define PMIC_MPP_PHYSICAL_OFFSET 1 |
98 | |
99 | /* Qualcomm specific pin configurations */ |
100 | #define PMIC_MPP_CONF_AMUX_ROUTE (PIN_CONFIG_END + 1) |
101 | #define PMIC_MPP_CONF_ANALOG_LEVEL (PIN_CONFIG_END + 2) |
102 | #define PMIC_MPP_CONF_DTEST_SELECTOR (PIN_CONFIG_END + 3) |
103 | #define PMIC_MPP_CONF_PAIRED (PIN_CONFIG_END + 4) |
104 | |
105 | /** |
106 | * struct pmic_mpp_pad - keep current MPP settings |
107 | * @base: Address base in SPMI device. |
108 | * @is_enabled: Set to false when MPP should be put in high Z state. |
109 | * @out_value: Cached pin output value. |
110 | * @output_enabled: Set to true if MPP output logic is enabled. |
111 | * @input_enabled: Set to true if MPP input buffer logic is enabled. |
112 | * @paired: Pin operates in paired mode |
113 | * @has_pullup: Pin has support to configure pullup |
114 | * @num_sources: Number of power-sources supported by this MPP. |
115 | * @power_source: Current power-source used. |
116 | * @amux_input: Set the source for analog input. |
117 | * @aout_level: Analog output level |
118 | * @pullup: Pullup resistor value. Valid in Bidirectional mode only. |
119 | * @function: See pmic_mpp_functions[]. |
120 | * @drive_strength: Amount of current in sink mode |
121 | * @dtest: DTEST route selector |
122 | */ |
123 | struct pmic_mpp_pad { |
124 | u16 base; |
125 | bool is_enabled; |
126 | bool out_value; |
127 | bool output_enabled; |
128 | bool input_enabled; |
129 | bool paired; |
130 | bool has_pullup; |
131 | unsigned int num_sources; |
132 | unsigned int power_source; |
133 | unsigned int amux_input; |
134 | unsigned int aout_level; |
135 | unsigned int pullup; |
136 | unsigned int function; |
137 | unsigned int drive_strength; |
138 | unsigned int dtest; |
139 | }; |
140 | |
141 | struct pmic_mpp_state { |
142 | struct device *dev; |
143 | struct regmap *map; |
144 | struct pinctrl_dev *ctrl; |
145 | struct gpio_chip chip; |
146 | }; |
147 | |
148 | static const struct pinconf_generic_params pmic_mpp_bindings[] = { |
149 | {"qcom,amux-route" , PMIC_MPP_CONF_AMUX_ROUTE, 0}, |
150 | {"qcom,analog-level" , PMIC_MPP_CONF_ANALOG_LEVEL, 0}, |
151 | {"qcom,dtest" , PMIC_MPP_CONF_DTEST_SELECTOR, 0}, |
152 | {"qcom,paired" , PMIC_MPP_CONF_PAIRED, 0}, |
153 | }; |
154 | |
155 | #ifdef CONFIG_DEBUG_FS |
156 | static const struct pin_config_item pmic_conf_items[] = { |
157 | PCONFDUMP(PMIC_MPP_CONF_AMUX_ROUTE, "analog mux" , NULL, true), |
158 | PCONFDUMP(PMIC_MPP_CONF_ANALOG_LEVEL, "analog level" , NULL, true), |
159 | PCONFDUMP(PMIC_MPP_CONF_DTEST_SELECTOR, "dtest" , NULL, true), |
160 | PCONFDUMP(PMIC_MPP_CONF_PAIRED, "paired" , NULL, false), |
161 | }; |
162 | #endif |
163 | |
164 | static const char *const pmic_mpp_groups[] = { |
165 | "mpp1" , "mpp2" , "mpp3" , "mpp4" , "mpp5" , "mpp6" , "mpp7" , "mpp8" , |
166 | }; |
167 | |
168 | #define PMIC_MPP_DIGITAL 0 |
169 | #define PMIC_MPP_ANALOG 1 |
170 | #define PMIC_MPP_SINK 2 |
171 | |
172 | static const char *const pmic_mpp_functions[] = { |
173 | "digital" , "analog" , "sink" |
174 | }; |
175 | |
176 | static int pmic_mpp_read(struct pmic_mpp_state *state, |
177 | struct pmic_mpp_pad *pad, unsigned int addr) |
178 | { |
179 | unsigned int val; |
180 | int ret; |
181 | |
182 | ret = regmap_read(map: state->map, reg: pad->base + addr, val: &val); |
183 | if (ret < 0) |
184 | dev_err(state->dev, "read 0x%x failed\n" , addr); |
185 | else |
186 | ret = val; |
187 | |
188 | return ret; |
189 | } |
190 | |
191 | static int pmic_mpp_write(struct pmic_mpp_state *state, |
192 | struct pmic_mpp_pad *pad, unsigned int addr, |
193 | unsigned int val) |
194 | { |
195 | int ret; |
196 | |
197 | ret = regmap_write(map: state->map, reg: pad->base + addr, val); |
198 | if (ret < 0) |
199 | dev_err(state->dev, "write 0x%x failed\n" , addr); |
200 | |
201 | return ret; |
202 | } |
203 | |
204 | static int pmic_mpp_get_groups_count(struct pinctrl_dev *pctldev) |
205 | { |
206 | /* Every PIN is a group */ |
207 | return pctldev->desc->npins; |
208 | } |
209 | |
210 | static const char *pmic_mpp_get_group_name(struct pinctrl_dev *pctldev, |
211 | unsigned pin) |
212 | { |
213 | return pctldev->desc->pins[pin].name; |
214 | } |
215 | |
216 | static int pmic_mpp_get_group_pins(struct pinctrl_dev *pctldev, |
217 | unsigned pin, |
218 | const unsigned **pins, unsigned *num_pins) |
219 | { |
220 | *pins = &pctldev->desc->pins[pin].number; |
221 | *num_pins = 1; |
222 | return 0; |
223 | } |
224 | |
225 | static const struct pinctrl_ops pmic_mpp_pinctrl_ops = { |
226 | .get_groups_count = pmic_mpp_get_groups_count, |
227 | .get_group_name = pmic_mpp_get_group_name, |
228 | .get_group_pins = pmic_mpp_get_group_pins, |
229 | .dt_node_to_map = pinconf_generic_dt_node_to_map_group, |
230 | .dt_free_map = pinctrl_utils_free_map, |
231 | }; |
232 | |
233 | static int pmic_mpp_get_functions_count(struct pinctrl_dev *pctldev) |
234 | { |
235 | return ARRAY_SIZE(pmic_mpp_functions); |
236 | } |
237 | |
238 | static const char *pmic_mpp_get_function_name(struct pinctrl_dev *pctldev, |
239 | unsigned function) |
240 | { |
241 | return pmic_mpp_functions[function]; |
242 | } |
243 | |
244 | static int pmic_mpp_get_function_groups(struct pinctrl_dev *pctldev, |
245 | unsigned function, |
246 | const char *const **groups, |
247 | unsigned *const num_qgroups) |
248 | { |
249 | *groups = pmic_mpp_groups; |
250 | *num_qgroups = pctldev->desc->npins; |
251 | return 0; |
252 | } |
253 | |
254 | static int pmic_mpp_write_mode_ctl(struct pmic_mpp_state *state, |
255 | struct pmic_mpp_pad *pad) |
256 | { |
257 | unsigned int mode; |
258 | unsigned int sel; |
259 | unsigned int val; |
260 | unsigned int en; |
261 | |
262 | switch (pad->function) { |
263 | case PMIC_MPP_ANALOG: |
264 | if (pad->input_enabled && pad->output_enabled) |
265 | mode = PMIC_MPP_MODE_ANALOG_BIDIR; |
266 | else if (pad->input_enabled) |
267 | mode = PMIC_MPP_MODE_ANALOG_INPUT; |
268 | else |
269 | mode = PMIC_MPP_MODE_ANALOG_OUTPUT; |
270 | break; |
271 | case PMIC_MPP_DIGITAL: |
272 | if (pad->input_enabled && pad->output_enabled) |
273 | mode = PMIC_MPP_MODE_DIGITAL_BIDIR; |
274 | else if (pad->input_enabled) |
275 | mode = PMIC_MPP_MODE_DIGITAL_INPUT; |
276 | else |
277 | mode = PMIC_MPP_MODE_DIGITAL_OUTPUT; |
278 | break; |
279 | case PMIC_MPP_SINK: |
280 | default: |
281 | mode = PMIC_MPP_MODE_CURRENT_SINK; |
282 | break; |
283 | } |
284 | |
285 | if (pad->dtest) |
286 | sel = PMIC_MPP_SELECTOR_DTEST_FIRST + pad->dtest - 1; |
287 | else if (pad->paired) |
288 | sel = PMIC_MPP_SELECTOR_PAIRED; |
289 | else |
290 | sel = PMIC_MPP_SELECTOR_NORMAL; |
291 | |
292 | en = !!pad->out_value; |
293 | |
294 | val = mode << PMIC_MPP_REG_MODE_DIR_SHIFT | |
295 | sel << PMIC_MPP_REG_MODE_FUNCTION_SHIFT | |
296 | en; |
297 | |
298 | return pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); |
299 | } |
300 | |
301 | static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function, |
302 | unsigned pin) |
303 | { |
304 | struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev); |
305 | struct pmic_mpp_pad *pad; |
306 | unsigned int val; |
307 | int ret; |
308 | |
309 | pad = pctldev->desc->pins[pin].drv_data; |
310 | |
311 | pad->function = function; |
312 | |
313 | ret = pmic_mpp_write_mode_ctl(state, pad); |
314 | if (ret < 0) |
315 | return ret; |
316 | |
317 | val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT; |
318 | |
319 | return pmic_mpp_write(state, pad, PMIC_MPP_REG_EN_CTL, val); |
320 | } |
321 | |
322 | static const struct pinmux_ops pmic_mpp_pinmux_ops = { |
323 | .get_functions_count = pmic_mpp_get_functions_count, |
324 | .get_function_name = pmic_mpp_get_function_name, |
325 | .get_function_groups = pmic_mpp_get_function_groups, |
326 | .set_mux = pmic_mpp_set_mux, |
327 | }; |
328 | |
329 | static int pmic_mpp_config_get(struct pinctrl_dev *pctldev, |
330 | unsigned int pin, unsigned long *config) |
331 | { |
332 | unsigned param = pinconf_to_config_param(config: *config); |
333 | struct pmic_mpp_pad *pad; |
334 | unsigned arg = 0; |
335 | |
336 | pad = pctldev->desc->pins[pin].drv_data; |
337 | |
338 | switch (param) { |
339 | case PIN_CONFIG_BIAS_DISABLE: |
340 | if (pad->pullup != PMIC_MPP_PULL_UP_OPEN) |
341 | return -EINVAL; |
342 | arg = 1; |
343 | break; |
344 | case PIN_CONFIG_BIAS_PULL_UP: |
345 | switch (pad->pullup) { |
346 | case PMIC_MPP_PULL_UP_0P6KOHM: |
347 | arg = 600; |
348 | break; |
349 | case PMIC_MPP_PULL_UP_10KOHM: |
350 | arg = 10000; |
351 | break; |
352 | case PMIC_MPP_PULL_UP_30KOHM: |
353 | arg = 30000; |
354 | break; |
355 | default: |
356 | return -EINVAL; |
357 | } |
358 | break; |
359 | case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: |
360 | if (pad->is_enabled) |
361 | return -EINVAL; |
362 | arg = 1; |
363 | break; |
364 | case PIN_CONFIG_POWER_SOURCE: |
365 | arg = pad->power_source; |
366 | break; |
367 | case PIN_CONFIG_INPUT_ENABLE: |
368 | if (!pad->input_enabled) |
369 | return -EINVAL; |
370 | arg = 1; |
371 | break; |
372 | case PIN_CONFIG_OUTPUT: |
373 | arg = pad->out_value; |
374 | break; |
375 | case PMIC_MPP_CONF_DTEST_SELECTOR: |
376 | arg = pad->dtest; |
377 | break; |
378 | case PMIC_MPP_CONF_AMUX_ROUTE: |
379 | arg = pad->amux_input; |
380 | break; |
381 | case PMIC_MPP_CONF_PAIRED: |
382 | if (!pad->paired) |
383 | return -EINVAL; |
384 | arg = 1; |
385 | break; |
386 | case PIN_CONFIG_DRIVE_STRENGTH: |
387 | arg = pad->drive_strength; |
388 | break; |
389 | case PMIC_MPP_CONF_ANALOG_LEVEL: |
390 | arg = pad->aout_level; |
391 | break; |
392 | default: |
393 | return -EINVAL; |
394 | } |
395 | |
396 | /* Convert register value to pinconf value */ |
397 | *config = pinconf_to_config_packed(param, argument: arg); |
398 | return 0; |
399 | } |
400 | |
401 | static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, |
402 | unsigned long *configs, unsigned nconfs) |
403 | { |
404 | struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev); |
405 | struct pmic_mpp_pad *pad; |
406 | unsigned param, arg; |
407 | unsigned int val; |
408 | int i, ret; |
409 | |
410 | pad = pctldev->desc->pins[pin].drv_data; |
411 | |
412 | /* Make it possible to enable the pin, by not setting high impedance */ |
413 | pad->is_enabled = true; |
414 | |
415 | for (i = 0; i < nconfs; i++) { |
416 | param = pinconf_to_config_param(config: configs[i]); |
417 | arg = pinconf_to_config_argument(config: configs[i]); |
418 | |
419 | switch (param) { |
420 | case PIN_CONFIG_BIAS_DISABLE: |
421 | pad->pullup = PMIC_MPP_PULL_UP_OPEN; |
422 | break; |
423 | case PIN_CONFIG_BIAS_PULL_UP: |
424 | switch (arg) { |
425 | case 600: |
426 | pad->pullup = PMIC_MPP_PULL_UP_0P6KOHM; |
427 | break; |
428 | case 10000: |
429 | pad->pullup = PMIC_MPP_PULL_UP_10KOHM; |
430 | break; |
431 | case 30000: |
432 | pad->pullup = PMIC_MPP_PULL_UP_30KOHM; |
433 | break; |
434 | default: |
435 | return -EINVAL; |
436 | } |
437 | break; |
438 | case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: |
439 | pad->is_enabled = false; |
440 | break; |
441 | case PIN_CONFIG_POWER_SOURCE: |
442 | if (arg >= pad->num_sources) |
443 | return -EINVAL; |
444 | pad->power_source = arg; |
445 | break; |
446 | case PIN_CONFIG_INPUT_ENABLE: |
447 | pad->input_enabled = arg ? true : false; |
448 | break; |
449 | case PIN_CONFIG_OUTPUT: |
450 | pad->output_enabled = true; |
451 | pad->out_value = arg; |
452 | break; |
453 | case PMIC_MPP_CONF_DTEST_SELECTOR: |
454 | pad->dtest = arg; |
455 | break; |
456 | case PIN_CONFIG_DRIVE_STRENGTH: |
457 | pad->drive_strength = arg; |
458 | break; |
459 | case PMIC_MPP_CONF_AMUX_ROUTE: |
460 | if (arg >= PMIC_MPP_AMUX_ROUTE_ABUS4) |
461 | return -EINVAL; |
462 | pad->amux_input = arg; |
463 | break; |
464 | case PMIC_MPP_CONF_ANALOG_LEVEL: |
465 | pad->aout_level = arg; |
466 | break; |
467 | case PMIC_MPP_CONF_PAIRED: |
468 | pad->paired = !!arg; |
469 | break; |
470 | default: |
471 | return -EINVAL; |
472 | } |
473 | } |
474 | |
475 | val = pad->power_source << PMIC_MPP_REG_VIN_SHIFT; |
476 | |
477 | ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_DIG_VIN_CTL, val); |
478 | if (ret < 0) |
479 | return ret; |
480 | |
481 | if (pad->has_pullup) { |
482 | val = pad->pullup << PMIC_MPP_REG_PULL_SHIFT; |
483 | |
484 | ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_DIG_PULL_CTL, |
485 | val); |
486 | if (ret < 0) |
487 | return ret; |
488 | } |
489 | |
490 | val = pad->amux_input & PMIC_MPP_REG_AIN_ROUTE_MASK; |
491 | |
492 | ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_AIN_CTL, val); |
493 | if (ret < 0) |
494 | return ret; |
495 | |
496 | ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_AOUT_CTL, val: pad->aout_level); |
497 | if (ret < 0) |
498 | return ret; |
499 | |
500 | ret = pmic_mpp_write_mode_ctl(state, pad); |
501 | if (ret < 0) |
502 | return ret; |
503 | |
504 | ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_SINK_CTL, val: pad->drive_strength); |
505 | if (ret < 0) |
506 | return ret; |
507 | |
508 | val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT; |
509 | |
510 | return pmic_mpp_write(state, pad, PMIC_MPP_REG_EN_CTL, val); |
511 | } |
512 | |
513 | static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, |
514 | struct seq_file *s, unsigned pin) |
515 | { |
516 | struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev); |
517 | struct pmic_mpp_pad *pad; |
518 | int ret; |
519 | |
520 | static const char *const biases[] = { |
521 | "0.6kOhm" , "10kOhm" , "30kOhm" , "Disabled" |
522 | }; |
523 | |
524 | pad = pctldev->desc->pins[pin].drv_data; |
525 | |
526 | seq_printf(m: s, fmt: " mpp%-2d:" , pin + PMIC_MPP_PHYSICAL_OFFSET); |
527 | |
528 | if (!pad->is_enabled) { |
529 | seq_puts(m: s, s: " ---" ); |
530 | } else { |
531 | |
532 | if (pad->input_enabled) { |
533 | ret = pmic_mpp_read(state, pad, PMIC_MPP_REG_RT_STS); |
534 | if (ret < 0) |
535 | return; |
536 | |
537 | ret &= PMIC_MPP_REG_RT_STS_VAL_MASK; |
538 | pad->out_value = ret; |
539 | } |
540 | |
541 | seq_printf(m: s, fmt: " %-4s" , pad->output_enabled ? "out" : "in" ); |
542 | seq_printf(m: s, fmt: " %-7s" , pmic_mpp_functions[pad->function]); |
543 | seq_printf(m: s, fmt: " vin-%d" , pad->power_source); |
544 | seq_printf(m: s, fmt: " %d" , pad->aout_level); |
545 | if (pad->has_pullup) |
546 | seq_printf(m: s, fmt: " %-8s" , biases[pad->pullup]); |
547 | seq_printf(m: s, fmt: " %-4s" , pad->out_value ? "high" : "low" ); |
548 | if (pad->dtest) |
549 | seq_printf(m: s, fmt: " dtest%d" , pad->dtest); |
550 | if (pad->paired) |
551 | seq_puts(m: s, s: " paired" ); |
552 | } |
553 | } |
554 | |
555 | static const struct pinconf_ops pmic_mpp_pinconf_ops = { |
556 | .is_generic = true, |
557 | .pin_config_group_get = pmic_mpp_config_get, |
558 | .pin_config_group_set = pmic_mpp_config_set, |
559 | .pin_config_group_dbg_show = pmic_mpp_config_dbg_show, |
560 | }; |
561 | |
562 | static int pmic_mpp_direction_input(struct gpio_chip *chip, unsigned pin) |
563 | { |
564 | struct pmic_mpp_state *state = gpiochip_get_data(gc: chip); |
565 | unsigned long config; |
566 | |
567 | config = pinconf_to_config_packed(param: PIN_CONFIG_INPUT_ENABLE, argument: 1); |
568 | |
569 | return pmic_mpp_config_set(pctldev: state->ctrl, pin, configs: &config, nconfs: 1); |
570 | } |
571 | |
572 | static int pmic_mpp_direction_output(struct gpio_chip *chip, |
573 | unsigned pin, int val) |
574 | { |
575 | struct pmic_mpp_state *state = gpiochip_get_data(gc: chip); |
576 | unsigned long config; |
577 | |
578 | config = pinconf_to_config_packed(param: PIN_CONFIG_OUTPUT, argument: val); |
579 | |
580 | return pmic_mpp_config_set(pctldev: state->ctrl, pin, configs: &config, nconfs: 1); |
581 | } |
582 | |
583 | static int pmic_mpp_get(struct gpio_chip *chip, unsigned pin) |
584 | { |
585 | struct pmic_mpp_state *state = gpiochip_get_data(gc: chip); |
586 | struct pmic_mpp_pad *pad; |
587 | int ret; |
588 | |
589 | pad = state->ctrl->desc->pins[pin].drv_data; |
590 | |
591 | if (pad->input_enabled) { |
592 | ret = pmic_mpp_read(state, pad, PMIC_MPP_REG_RT_STS); |
593 | if (ret < 0) |
594 | return ret; |
595 | |
596 | pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK; |
597 | } |
598 | |
599 | return !!pad->out_value; |
600 | } |
601 | |
602 | static void pmic_mpp_set(struct gpio_chip *chip, unsigned pin, int value) |
603 | { |
604 | struct pmic_mpp_state *state = gpiochip_get_data(gc: chip); |
605 | unsigned long config; |
606 | |
607 | config = pinconf_to_config_packed(param: PIN_CONFIG_OUTPUT, argument: value); |
608 | |
609 | pmic_mpp_config_set(pctldev: state->ctrl, pin, configs: &config, nconfs: 1); |
610 | } |
611 | |
612 | static int pmic_mpp_of_xlate(struct gpio_chip *chip, |
613 | const struct of_phandle_args *gpio_desc, |
614 | u32 *flags) |
615 | { |
616 | if (chip->of_gpio_n_cells < 2) |
617 | return -EINVAL; |
618 | |
619 | if (flags) |
620 | *flags = gpio_desc->args[1]; |
621 | |
622 | return gpio_desc->args[0] - PMIC_MPP_PHYSICAL_OFFSET; |
623 | } |
624 | |
625 | static void pmic_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip) |
626 | { |
627 | struct pmic_mpp_state *state = gpiochip_get_data(gc: chip); |
628 | unsigned i; |
629 | |
630 | for (i = 0; i < chip->ngpio; i++) { |
631 | pmic_mpp_config_dbg_show(pctldev: state->ctrl, s, pin: i); |
632 | seq_puts(m: s, s: "\n" ); |
633 | } |
634 | } |
635 | |
636 | static const struct gpio_chip pmic_mpp_gpio_template = { |
637 | .direction_input = pmic_mpp_direction_input, |
638 | .direction_output = pmic_mpp_direction_output, |
639 | .get = pmic_mpp_get, |
640 | .set = pmic_mpp_set, |
641 | .request = gpiochip_generic_request, |
642 | .free = gpiochip_generic_free, |
643 | .of_xlate = pmic_mpp_of_xlate, |
644 | .dbg_show = pmic_mpp_dbg_show, |
645 | }; |
646 | |
647 | static int pmic_mpp_populate(struct pmic_mpp_state *state, |
648 | struct pmic_mpp_pad *pad) |
649 | { |
650 | int type, subtype, val, dir; |
651 | unsigned int sel; |
652 | |
653 | type = pmic_mpp_read(state, pad, PMIC_MPP_REG_TYPE); |
654 | if (type < 0) |
655 | return type; |
656 | |
657 | if (type != PMIC_MPP_TYPE) { |
658 | dev_err(state->dev, "incorrect block type 0x%x at 0x%x\n" , |
659 | type, pad->base); |
660 | return -ENODEV; |
661 | } |
662 | |
663 | subtype = pmic_mpp_read(state, pad, PMIC_MPP_REG_SUBTYPE); |
664 | if (subtype < 0) |
665 | return subtype; |
666 | |
667 | switch (subtype) { |
668 | case PMIC_MPP_SUBTYPE_4CH_NO_ANA_OUT: |
669 | case PMIC_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT: |
670 | case PMIC_MPP_SUBTYPE_4CH_NO_SINK: |
671 | case PMIC_MPP_SUBTYPE_ULT_4CH_NO_SINK: |
672 | case PMIC_MPP_SUBTYPE_4CH_FULL_FUNC: |
673 | pad->num_sources = 4; |
674 | break; |
675 | case PMIC_MPP_SUBTYPE_8CH_FULL_FUNC: |
676 | pad->num_sources = 8; |
677 | break; |
678 | default: |
679 | dev_err(state->dev, "unknown MPP type 0x%x at 0x%x\n" , |
680 | subtype, pad->base); |
681 | return -ENODEV; |
682 | } |
683 | |
684 | val = pmic_mpp_read(state, pad, PMIC_MPP_REG_MODE_CTL); |
685 | if (val < 0) |
686 | return val; |
687 | |
688 | pad->out_value = val & PMIC_MPP_REG_MODE_VALUE_MASK; |
689 | |
690 | dir = val >> PMIC_MPP_REG_MODE_DIR_SHIFT; |
691 | dir &= PMIC_MPP_REG_MODE_DIR_MASK; |
692 | |
693 | switch (dir) { |
694 | case PMIC_MPP_MODE_DIGITAL_INPUT: |
695 | pad->input_enabled = true; |
696 | pad->output_enabled = false; |
697 | pad->function = PMIC_MPP_DIGITAL; |
698 | break; |
699 | case PMIC_MPP_MODE_DIGITAL_OUTPUT: |
700 | pad->input_enabled = false; |
701 | pad->output_enabled = true; |
702 | pad->function = PMIC_MPP_DIGITAL; |
703 | break; |
704 | case PMIC_MPP_MODE_DIGITAL_BIDIR: |
705 | pad->input_enabled = true; |
706 | pad->output_enabled = true; |
707 | pad->function = PMIC_MPP_DIGITAL; |
708 | break; |
709 | case PMIC_MPP_MODE_ANALOG_BIDIR: |
710 | pad->input_enabled = true; |
711 | pad->output_enabled = true; |
712 | pad->function = PMIC_MPP_ANALOG; |
713 | break; |
714 | case PMIC_MPP_MODE_ANALOG_INPUT: |
715 | pad->input_enabled = true; |
716 | pad->output_enabled = false; |
717 | pad->function = PMIC_MPP_ANALOG; |
718 | break; |
719 | case PMIC_MPP_MODE_ANALOG_OUTPUT: |
720 | pad->input_enabled = false; |
721 | pad->output_enabled = true; |
722 | pad->function = PMIC_MPP_ANALOG; |
723 | break; |
724 | case PMIC_MPP_MODE_CURRENT_SINK: |
725 | pad->input_enabled = false; |
726 | pad->output_enabled = true; |
727 | pad->function = PMIC_MPP_SINK; |
728 | break; |
729 | default: |
730 | dev_err(state->dev, "unknown MPP direction\n" ); |
731 | return -ENODEV; |
732 | } |
733 | |
734 | sel = val >> PMIC_MPP_REG_MODE_FUNCTION_SHIFT; |
735 | sel &= PMIC_MPP_REG_MODE_FUNCTION_MASK; |
736 | |
737 | if (sel >= PMIC_MPP_SELECTOR_DTEST_FIRST) |
738 | pad->dtest = sel + 1; |
739 | else if (sel == PMIC_MPP_SELECTOR_PAIRED) |
740 | pad->paired = true; |
741 | |
742 | val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_VIN_CTL); |
743 | if (val < 0) |
744 | return val; |
745 | |
746 | pad->power_source = val >> PMIC_MPP_REG_VIN_SHIFT; |
747 | pad->power_source &= PMIC_MPP_REG_VIN_MASK; |
748 | |
749 | if (subtype != PMIC_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT && |
750 | subtype != PMIC_MPP_SUBTYPE_ULT_4CH_NO_SINK) { |
751 | val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_PULL_CTL); |
752 | if (val < 0) |
753 | return val; |
754 | |
755 | pad->pullup = val >> PMIC_MPP_REG_PULL_SHIFT; |
756 | pad->pullup &= PMIC_MPP_REG_PULL_MASK; |
757 | pad->has_pullup = true; |
758 | } |
759 | |
760 | val = pmic_mpp_read(state, pad, PMIC_MPP_REG_AIN_CTL); |
761 | if (val < 0) |
762 | return val; |
763 | |
764 | pad->amux_input = val >> PMIC_MPP_REG_AIN_ROUTE_SHIFT; |
765 | pad->amux_input &= PMIC_MPP_REG_AIN_ROUTE_MASK; |
766 | |
767 | val = pmic_mpp_read(state, pad, PMIC_MPP_REG_SINK_CTL); |
768 | if (val < 0) |
769 | return val; |
770 | |
771 | pad->drive_strength = val; |
772 | |
773 | val = pmic_mpp_read(state, pad, PMIC_MPP_REG_AOUT_CTL); |
774 | if (val < 0) |
775 | return val; |
776 | |
777 | pad->aout_level = val; |
778 | |
779 | val = pmic_mpp_read(state, pad, PMIC_MPP_REG_EN_CTL); |
780 | if (val < 0) |
781 | return val; |
782 | |
783 | pad->is_enabled = !!val; |
784 | |
785 | return 0; |
786 | } |
787 | |
788 | static int pmic_mpp_domain_translate(struct irq_domain *domain, |
789 | struct irq_fwspec *fwspec, |
790 | unsigned long *hwirq, |
791 | unsigned int *type) |
792 | { |
793 | struct pmic_mpp_state *state = container_of(domain->host_data, |
794 | struct pmic_mpp_state, |
795 | chip); |
796 | |
797 | if (fwspec->param_count != 2 || |
798 | fwspec->param[0] < 1 || fwspec->param[0] > state->chip.ngpio) |
799 | return -EINVAL; |
800 | |
801 | *hwirq = fwspec->param[0] - PMIC_MPP_PHYSICAL_OFFSET; |
802 | *type = fwspec->param[1]; |
803 | |
804 | return 0; |
805 | } |
806 | |
807 | static unsigned int pmic_mpp_child_offset_to_irq(struct gpio_chip *chip, |
808 | unsigned int offset) |
809 | { |
810 | return offset + PMIC_MPP_PHYSICAL_OFFSET; |
811 | } |
812 | |
813 | static int pmic_mpp_child_to_parent_hwirq(struct gpio_chip *chip, |
814 | unsigned int child_hwirq, |
815 | unsigned int child_type, |
816 | unsigned int *parent_hwirq, |
817 | unsigned int *parent_type) |
818 | { |
819 | *parent_hwirq = child_hwirq + 0xc0; |
820 | *parent_type = child_type; |
821 | |
822 | return 0; |
823 | } |
824 | |
825 | static void pmic_mpp_irq_mask(struct irq_data *d) |
826 | { |
827 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
828 | |
829 | irq_chip_mask_parent(data: d); |
830 | gpiochip_disable_irq(gc, offset: irqd_to_hwirq(d)); |
831 | } |
832 | |
833 | static void pmic_mpp_irq_unmask(struct irq_data *d) |
834 | { |
835 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
836 | |
837 | gpiochip_enable_irq(gc, offset: irqd_to_hwirq(d)); |
838 | irq_chip_unmask_parent(data: d); |
839 | } |
840 | |
841 | static const struct irq_chip pmic_mpp_irq_chip = { |
842 | .name = "spmi-mpp" , |
843 | .irq_ack = irq_chip_ack_parent, |
844 | .irq_mask = pmic_mpp_irq_mask, |
845 | .irq_unmask = pmic_mpp_irq_unmask, |
846 | .irq_set_type = irq_chip_set_type_parent, |
847 | .irq_set_wake = irq_chip_set_wake_parent, |
848 | .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE, |
849 | GPIOCHIP_IRQ_RESOURCE_HELPERS, |
850 | }; |
851 | |
852 | static int pmic_mpp_probe(struct platform_device *pdev) |
853 | { |
854 | struct irq_domain *parent_domain; |
855 | struct device_node *parent_node; |
856 | struct device *dev = &pdev->dev; |
857 | struct pinctrl_pin_desc *pindesc; |
858 | struct pinctrl_desc *pctrldesc; |
859 | struct pmic_mpp_pad *pad, *pads; |
860 | struct pmic_mpp_state *state; |
861 | struct gpio_irq_chip *girq; |
862 | int ret, npins, i; |
863 | u32 reg; |
864 | |
865 | ret = of_property_read_u32(np: dev->of_node, propname: "reg" , out_value: ®); |
866 | if (ret < 0) { |
867 | dev_err(dev, "missing base address" ); |
868 | return ret; |
869 | } |
870 | |
871 | npins = (uintptr_t) device_get_match_data(dev: &pdev->dev); |
872 | |
873 | BUG_ON(npins > ARRAY_SIZE(pmic_mpp_groups)); |
874 | |
875 | state = devm_kzalloc(dev, size: sizeof(*state), GFP_KERNEL); |
876 | if (!state) |
877 | return -ENOMEM; |
878 | |
879 | platform_set_drvdata(pdev, data: state); |
880 | |
881 | state->dev = &pdev->dev; |
882 | state->map = dev_get_regmap(dev: dev->parent, NULL); |
883 | |
884 | pindesc = devm_kcalloc(dev, n: npins, size: sizeof(*pindesc), GFP_KERNEL); |
885 | if (!pindesc) |
886 | return -ENOMEM; |
887 | |
888 | pads = devm_kcalloc(dev, n: npins, size: sizeof(*pads), GFP_KERNEL); |
889 | if (!pads) |
890 | return -ENOMEM; |
891 | |
892 | pctrldesc = devm_kzalloc(dev, size: sizeof(*pctrldesc), GFP_KERNEL); |
893 | if (!pctrldesc) |
894 | return -ENOMEM; |
895 | |
896 | pctrldesc->pctlops = &pmic_mpp_pinctrl_ops; |
897 | pctrldesc->pmxops = &pmic_mpp_pinmux_ops; |
898 | pctrldesc->confops = &pmic_mpp_pinconf_ops; |
899 | pctrldesc->owner = THIS_MODULE; |
900 | pctrldesc->name = dev_name(dev); |
901 | pctrldesc->pins = pindesc; |
902 | pctrldesc->npins = npins; |
903 | |
904 | pctrldesc->num_custom_params = ARRAY_SIZE(pmic_mpp_bindings); |
905 | pctrldesc->custom_params = pmic_mpp_bindings; |
906 | #ifdef CONFIG_DEBUG_FS |
907 | pctrldesc->custom_conf_items = pmic_conf_items; |
908 | #endif |
909 | |
910 | for (i = 0; i < npins; i++, pindesc++) { |
911 | pad = &pads[i]; |
912 | pindesc->drv_data = pad; |
913 | pindesc->number = i; |
914 | pindesc->name = pmic_mpp_groups[i]; |
915 | |
916 | pad->base = reg + i * PMIC_MPP_ADDRESS_RANGE; |
917 | |
918 | ret = pmic_mpp_populate(state, pad); |
919 | if (ret < 0) |
920 | return ret; |
921 | } |
922 | |
923 | state->chip = pmic_mpp_gpio_template; |
924 | state->chip.parent = dev; |
925 | state->chip.base = -1; |
926 | state->chip.ngpio = npins; |
927 | state->chip.label = dev_name(dev); |
928 | state->chip.of_gpio_n_cells = 2; |
929 | state->chip.can_sleep = false; |
930 | |
931 | state->ctrl = devm_pinctrl_register(dev, pctldesc: pctrldesc, driver_data: state); |
932 | if (IS_ERR(ptr: state->ctrl)) |
933 | return PTR_ERR(ptr: state->ctrl); |
934 | |
935 | parent_node = of_irq_find_parent(child: state->dev->of_node); |
936 | if (!parent_node) |
937 | return -ENXIO; |
938 | |
939 | parent_domain = irq_find_host(node: parent_node); |
940 | of_node_put(node: parent_node); |
941 | if (!parent_domain) |
942 | return -ENXIO; |
943 | |
944 | girq = &state->chip.irq; |
945 | gpio_irq_chip_set_chip(girq, chip: &pmic_mpp_irq_chip); |
946 | girq->default_type = IRQ_TYPE_NONE; |
947 | girq->handler = handle_level_irq; |
948 | girq->fwnode = dev_fwnode(state->dev); |
949 | girq->parent_domain = parent_domain; |
950 | girq->child_to_parent_hwirq = pmic_mpp_child_to_parent_hwirq; |
951 | girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_fourcell; |
952 | girq->child_offset_to_irq = pmic_mpp_child_offset_to_irq; |
953 | girq->child_irq_domain_ops.translate = pmic_mpp_domain_translate; |
954 | |
955 | ret = gpiochip_add_data(&state->chip, state); |
956 | if (ret) { |
957 | dev_err(state->dev, "can't add gpio chip\n" ); |
958 | return ret; |
959 | } |
960 | |
961 | ret = gpiochip_add_pin_range(gc: &state->chip, pinctl_name: dev_name(dev), gpio_offset: 0, pin_offset: 0, npins); |
962 | if (ret) { |
963 | dev_err(dev, "failed to add pin range\n" ); |
964 | goto err_range; |
965 | } |
966 | |
967 | return 0; |
968 | |
969 | err_range: |
970 | gpiochip_remove(gc: &state->chip); |
971 | return ret; |
972 | } |
973 | |
974 | static void pmic_mpp_remove(struct platform_device *pdev) |
975 | { |
976 | struct pmic_mpp_state *state = platform_get_drvdata(pdev); |
977 | |
978 | gpiochip_remove(gc: &state->chip); |
979 | } |
980 | |
981 | static const struct of_device_id pmic_mpp_of_match[] = { |
982 | { .compatible = "qcom,pm8019-mpp" , .data = (void *) 6 }, |
983 | { .compatible = "qcom,pm8226-mpp" , .data = (void *) 8 }, |
984 | { .compatible = "qcom,pm8841-mpp" , .data = (void *) 4 }, |
985 | { .compatible = "qcom,pm8916-mpp" , .data = (void *) 4 }, |
986 | { .compatible = "qcom,pm8941-mpp" , .data = (void *) 8 }, |
987 | { .compatible = "qcom,pm8950-mpp" , .data = (void *) 4 }, |
988 | { .compatible = "qcom,pmi8950-mpp" , .data = (void *) 4 }, |
989 | { .compatible = "qcom,pm8994-mpp" , .data = (void *) 8 }, |
990 | { .compatible = "qcom,pma8084-mpp" , .data = (void *) 8 }, |
991 | { .compatible = "qcom,pmi8994-mpp" , .data = (void *) 4 }, |
992 | { }, |
993 | }; |
994 | |
995 | MODULE_DEVICE_TABLE(of, pmic_mpp_of_match); |
996 | |
997 | static struct platform_driver pmic_mpp_driver = { |
998 | .driver = { |
999 | .name = "qcom-spmi-mpp" , |
1000 | .of_match_table = pmic_mpp_of_match, |
1001 | }, |
1002 | .probe = pmic_mpp_probe, |
1003 | .remove_new = pmic_mpp_remove, |
1004 | }; |
1005 | |
1006 | module_platform_driver(pmic_mpp_driver); |
1007 | |
1008 | MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>" ); |
1009 | MODULE_DESCRIPTION("Qualcomm SPMI PMIC MPP pin control driver" ); |
1010 | MODULE_ALIAS("platform:qcom-spmi-mpp" ); |
1011 | MODULE_LICENSE("GPL v2" ); |
1012 | |