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