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