1eadff302SIvan T. Ivanov /*
2eadff302SIvan T. Ivanov  * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
3eadff302SIvan T. Ivanov  *
4eadff302SIvan T. Ivanov  * This program is free software; you can redistribute it and/or modify
5eadff302SIvan T. Ivanov  * it under the terms of the GNU General Public License version 2 and
6eadff302SIvan T. Ivanov  * only version 2 as published by the Free Software Foundation.
7eadff302SIvan T. Ivanov  *
8eadff302SIvan T. Ivanov  * This program is distributed in the hope that it will be useful,
9eadff302SIvan T. Ivanov  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10eadff302SIvan T. Ivanov  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11eadff302SIvan T. Ivanov  * GNU General Public License for more details.
12eadff302SIvan T. Ivanov  */
13eadff302SIvan T. Ivanov 
14eadff302SIvan T. Ivanov #include <linux/gpio.h>
15eadff302SIvan T. Ivanov #include <linux/module.h>
16eadff302SIvan T. Ivanov #include <linux/of.h>
17eadff302SIvan T. Ivanov #include <linux/pinctrl/pinconf-generic.h>
18eadff302SIvan T. Ivanov #include <linux/pinctrl/pinconf.h>
19eadff302SIvan T. Ivanov #include <linux/pinctrl/pinmux.h>
20eadff302SIvan T. Ivanov #include <linux/platform_device.h>
21eadff302SIvan T. Ivanov #include <linux/regmap.h>
22eadff302SIvan T. Ivanov #include <linux/slab.h>
23eadff302SIvan T. Ivanov #include <linux/types.h>
24eadff302SIvan T. Ivanov 
25eadff302SIvan T. Ivanov #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
26eadff302SIvan T. Ivanov 
27eadff302SIvan T. Ivanov #include "../core.h"
28eadff302SIvan T. Ivanov #include "../pinctrl-utils.h"
29eadff302SIvan T. Ivanov 
30eadff302SIvan T. Ivanov #define PMIC_GPIO_ADDRESS_RANGE			0x100
31eadff302SIvan T. Ivanov 
32eadff302SIvan T. Ivanov /* type and subtype registers base address offsets */
33eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_TYPE			0x4
34eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_SUBTYPE			0x5
35eadff302SIvan T. Ivanov 
36eadff302SIvan T. Ivanov /* GPIO peripheral type and subtype out_values */
37eadff302SIvan T. Ivanov #define PMIC_GPIO_TYPE				0x10
38eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIO_4CH		0x1
39eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIOC_4CH		0x5
40eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIO_8CH		0x9
41eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIOC_8CH		0xd
42eadff302SIvan T. Ivanov 
43eadff302SIvan T. Ivanov #define PMIC_MPP_REG_RT_STS			0x10
44eadff302SIvan T. Ivanov #define PMIC_MPP_REG_RT_STS_VAL_MASK		0x1
45eadff302SIvan T. Ivanov 
46eadff302SIvan T. Ivanov /* control register base address offsets */
47eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_CTL			0x40
48eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_DIG_VIN_CTL		0x41
49eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_DIG_PULL_CTL		0x42
50eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_DIG_OUT_CTL		0x45
51eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_EN_CTL			0x46
52eadff302SIvan T. Ivanov 
53eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_MODE_CTL */
54eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_VALUE_SHIFT		0x1
55eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_FUNCTION_SHIFT	1
56eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_FUNCTION_MASK	0x7
57eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_DIR_SHIFT		4
58eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_DIR_MASK		0x7
59eadff302SIvan T. Ivanov 
60eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_DIG_VIN_CTL */
61eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_VIN_SHIFT			0
62eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_VIN_MASK			0x7
63eadff302SIvan T. Ivanov 
64eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_DIG_PULL_CTL */
65eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_PULL_SHIFT		0
66eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_PULL_MASK			0x7
67eadff302SIvan T. Ivanov 
68eadff302SIvan T. Ivanov #define PMIC_GPIO_PULL_DOWN			4
69eadff302SIvan T. Ivanov #define PMIC_GPIO_PULL_DISABLE			5
70eadff302SIvan T. Ivanov 
71eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_DIG_OUT_CTL */
72eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_STRENGTH_SHIFT	0
73eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_STRENGTH_MASK		0x3
74eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_TYPE_SHIFT		4
75eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_TYPE_MASK		0x3
76eadff302SIvan T. Ivanov 
77eadff302SIvan T. Ivanov /*
78eadff302SIvan T. Ivanov  * Output type - indicates pin should be configured as push-pull,
79eadff302SIvan T. Ivanov  * open drain or open source.
80eadff302SIvan T. Ivanov  */
81eadff302SIvan T. Ivanov #define PMIC_GPIO_OUT_BUF_CMOS			0
82eadff302SIvan T. Ivanov #define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS	1
83eadff302SIvan T. Ivanov #define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS	2
84eadff302SIvan T. Ivanov 
85eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_EN_CTL */
86eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MASTER_EN_SHIFT		7
87eadff302SIvan T. Ivanov 
88eadff302SIvan T. Ivanov #define PMIC_GPIO_PHYSICAL_OFFSET		1
89eadff302SIvan T. Ivanov 
90eadff302SIvan T. Ivanov /* Qualcomm specific pin configurations */
91eadff302SIvan T. Ivanov #define PMIC_GPIO_CONF_PULL_UP			(PIN_CONFIG_END + 1)
92eadff302SIvan T. Ivanov #define PMIC_GPIO_CONF_STRENGTH			(PIN_CONFIG_END + 2)
93eadff302SIvan T. Ivanov 
94eadff302SIvan T. Ivanov /**
95eadff302SIvan T. Ivanov  * struct pmic_gpio_pad - keep current GPIO settings
96eadff302SIvan T. Ivanov  * @base: Address base in SPMI device.
97eadff302SIvan T. Ivanov  * @irq: IRQ number which this GPIO generate.
98eadff302SIvan T. Ivanov  * @is_enabled: Set to false when GPIO should be put in high Z state.
99eadff302SIvan T. Ivanov  * @out_value: Cached pin output value
100eadff302SIvan T. Ivanov  * @have_buffer: Set to true if GPIO output could be configured in push-pull,
101eadff302SIvan T. Ivanov  *	open-drain or open-source mode.
102eadff302SIvan T. Ivanov  * @output_enabled: Set to true if GPIO output logic is enabled.
103eadff302SIvan T. Ivanov  * @input_enabled: Set to true if GPIO input buffer logic is enabled.
104eadff302SIvan T. Ivanov  * @num_sources: Number of power-sources supported by this GPIO.
105eadff302SIvan T. Ivanov  * @power_source: Current power-source used.
106eadff302SIvan T. Ivanov  * @buffer_type: Push-pull, open-drain or open-source.
107eadff302SIvan T. Ivanov  * @pullup: Constant current which flow trough GPIO output buffer.
108eadff302SIvan T. Ivanov  * @strength: No, Low, Medium, High
109eadff302SIvan T. Ivanov  * @function: See pmic_gpio_functions[]
110eadff302SIvan T. Ivanov  */
111eadff302SIvan T. Ivanov struct pmic_gpio_pad {
112eadff302SIvan T. Ivanov 	u16		base;
113eadff302SIvan T. Ivanov 	int		irq;
114eadff302SIvan T. Ivanov 	bool		is_enabled;
115eadff302SIvan T. Ivanov 	bool		out_value;
116eadff302SIvan T. Ivanov 	bool		have_buffer;
117eadff302SIvan T. Ivanov 	bool		output_enabled;
118eadff302SIvan T. Ivanov 	bool		input_enabled;
119eadff302SIvan T. Ivanov 	unsigned int	num_sources;
120eadff302SIvan T. Ivanov 	unsigned int	power_source;
121eadff302SIvan T. Ivanov 	unsigned int	buffer_type;
122eadff302SIvan T. Ivanov 	unsigned int	pullup;
123eadff302SIvan T. Ivanov 	unsigned int	strength;
124eadff302SIvan T. Ivanov 	unsigned int	function;
125eadff302SIvan T. Ivanov };
126eadff302SIvan T. Ivanov 
127eadff302SIvan T. Ivanov struct pmic_gpio_state {
128eadff302SIvan T. Ivanov 	struct device	*dev;
129eadff302SIvan T. Ivanov 	struct regmap	*map;
130eadff302SIvan T. Ivanov 	struct pinctrl_dev *ctrl;
131eadff302SIvan T. Ivanov 	struct gpio_chip chip;
132eadff302SIvan T. Ivanov };
133eadff302SIvan T. Ivanov 
134f684e4acSLinus Walleij static const struct pinconf_generic_params pmic_gpio_bindings[] = {
1357382b623SSoren Brinkmann 	{"qcom,pull-up-strength",	PMIC_GPIO_CONF_PULL_UP,		0},
1367382b623SSoren Brinkmann 	{"qcom,drive-strength",		PMIC_GPIO_CONF_STRENGTH,	0},
137eadff302SIvan T. Ivanov };
138eadff302SIvan T. Ivanov 
1394f06266aSArnd Bergmann #ifdef CONFIG_DEBUG_FS
1407382b623SSoren Brinkmann static const struct pin_config_item pmic_conf_items[ARRAY_SIZE(pmic_gpio_bindings)] = {
1417382b623SSoren Brinkmann 	PCONFDUMP(PMIC_GPIO_CONF_PULL_UP,  "pull up strength", NULL, true),
1427382b623SSoren Brinkmann 	PCONFDUMP(PMIC_GPIO_CONF_STRENGTH, "drive-strength", NULL, true),
143eadff302SIvan T. Ivanov };
1444f06266aSArnd Bergmann #endif
145eadff302SIvan T. Ivanov 
146eadff302SIvan T. Ivanov static const char *const pmic_gpio_groups[] = {
147eadff302SIvan T. Ivanov 	"gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", "gpio8",
148eadff302SIvan T. Ivanov 	"gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", "gpio15",
149eadff302SIvan T. Ivanov 	"gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", "gpio22",
150eadff302SIvan T. Ivanov 	"gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29",
151eadff302SIvan T. Ivanov 	"gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36",
152eadff302SIvan T. Ivanov };
153eadff302SIvan T. Ivanov 
154eadff302SIvan T. Ivanov static const char *const pmic_gpio_functions[] = {
155eadff302SIvan T. Ivanov 	PMIC_GPIO_FUNC_NORMAL, PMIC_GPIO_FUNC_PAIRED,
156eadff302SIvan T. Ivanov 	PMIC_GPIO_FUNC_FUNC1, PMIC_GPIO_FUNC_FUNC2,
157eadff302SIvan T. Ivanov 	PMIC_GPIO_FUNC_DTEST1, PMIC_GPIO_FUNC_DTEST2,
158eadff302SIvan T. Ivanov 	PMIC_GPIO_FUNC_DTEST3, PMIC_GPIO_FUNC_DTEST4,
159eadff302SIvan T. Ivanov };
160eadff302SIvan T. Ivanov 
161eadff302SIvan T. Ivanov static inline struct pmic_gpio_state *to_gpio_state(struct gpio_chip *chip)
162eadff302SIvan T. Ivanov {
163eadff302SIvan T. Ivanov 	return container_of(chip, struct pmic_gpio_state, chip);
164eadff302SIvan T. Ivanov };
165eadff302SIvan T. Ivanov 
166eadff302SIvan T. Ivanov static int pmic_gpio_read(struct pmic_gpio_state *state,
167eadff302SIvan T. Ivanov 			  struct pmic_gpio_pad *pad, unsigned int addr)
168eadff302SIvan T. Ivanov {
169eadff302SIvan T. Ivanov 	unsigned int val;
170eadff302SIvan T. Ivanov 	int ret;
171eadff302SIvan T. Ivanov 
172eadff302SIvan T. Ivanov 	ret = regmap_read(state->map, pad->base + addr, &val);
173eadff302SIvan T. Ivanov 	if (ret < 0)
174eadff302SIvan T. Ivanov 		dev_err(state->dev, "read 0x%x failed\n", addr);
175eadff302SIvan T. Ivanov 	else
176eadff302SIvan T. Ivanov 		ret = val;
177eadff302SIvan T. Ivanov 
178eadff302SIvan T. Ivanov 	return ret;
179eadff302SIvan T. Ivanov }
180eadff302SIvan T. Ivanov 
181eadff302SIvan T. Ivanov static int pmic_gpio_write(struct pmic_gpio_state *state,
182eadff302SIvan T. Ivanov 			   struct pmic_gpio_pad *pad, unsigned int addr,
183eadff302SIvan T. Ivanov 			   unsigned int val)
184eadff302SIvan T. Ivanov {
185eadff302SIvan T. Ivanov 	int ret;
186eadff302SIvan T. Ivanov 
187eadff302SIvan T. Ivanov 	ret = regmap_write(state->map, pad->base + addr, val);
188eadff302SIvan T. Ivanov 	if (ret < 0)
189eadff302SIvan T. Ivanov 		dev_err(state->dev, "write 0x%x failed\n", addr);
190eadff302SIvan T. Ivanov 
191eadff302SIvan T. Ivanov 	return ret;
192eadff302SIvan T. Ivanov }
193eadff302SIvan T. Ivanov 
194eadff302SIvan T. Ivanov static int pmic_gpio_get_groups_count(struct pinctrl_dev *pctldev)
195eadff302SIvan T. Ivanov {
196eadff302SIvan T. Ivanov 	/* Every PIN is a group */
197eadff302SIvan T. Ivanov 	return pctldev->desc->npins;
198eadff302SIvan T. Ivanov }
199eadff302SIvan T. Ivanov 
200eadff302SIvan T. Ivanov static const char *pmic_gpio_get_group_name(struct pinctrl_dev *pctldev,
201eadff302SIvan T. Ivanov 					    unsigned pin)
202eadff302SIvan T. Ivanov {
203eadff302SIvan T. Ivanov 	return pctldev->desc->pins[pin].name;
204eadff302SIvan T. Ivanov }
205eadff302SIvan T. Ivanov 
206eadff302SIvan T. Ivanov static int pmic_gpio_get_group_pins(struct pinctrl_dev *pctldev, unsigned pin,
207eadff302SIvan T. Ivanov 				    const unsigned **pins, unsigned *num_pins)
208eadff302SIvan T. Ivanov {
209eadff302SIvan T. Ivanov 	*pins = &pctldev->desc->pins[pin].number;
210eadff302SIvan T. Ivanov 	*num_pins = 1;
211eadff302SIvan T. Ivanov 	return 0;
212eadff302SIvan T. Ivanov }
213eadff302SIvan T. Ivanov 
214eadff302SIvan T. Ivanov static const struct pinctrl_ops pmic_gpio_pinctrl_ops = {
215eadff302SIvan T. Ivanov 	.get_groups_count	= pmic_gpio_get_groups_count,
216eadff302SIvan T. Ivanov 	.get_group_name		= pmic_gpio_get_group_name,
217eadff302SIvan T. Ivanov 	.get_group_pins		= pmic_gpio_get_group_pins,
2187382b623SSoren Brinkmann 	.dt_node_to_map		= pinconf_generic_dt_node_to_map_group,
219eadff302SIvan T. Ivanov 	.dt_free_map		= pinctrl_utils_dt_free_map,
220eadff302SIvan T. Ivanov };
221eadff302SIvan T. Ivanov 
222eadff302SIvan T. Ivanov static int pmic_gpio_get_functions_count(struct pinctrl_dev *pctldev)
223eadff302SIvan T. Ivanov {
224eadff302SIvan T. Ivanov 	return ARRAY_SIZE(pmic_gpio_functions);
225eadff302SIvan T. Ivanov }
226eadff302SIvan T. Ivanov 
227eadff302SIvan T. Ivanov static const char *pmic_gpio_get_function_name(struct pinctrl_dev *pctldev,
228eadff302SIvan T. Ivanov 					       unsigned function)
229eadff302SIvan T. Ivanov {
230eadff302SIvan T. Ivanov 	return pmic_gpio_functions[function];
231eadff302SIvan T. Ivanov }
232eadff302SIvan T. Ivanov 
233eadff302SIvan T. Ivanov static int pmic_gpio_get_function_groups(struct pinctrl_dev *pctldev,
234eadff302SIvan T. Ivanov 					 unsigned function,
235eadff302SIvan T. Ivanov 					 const char *const **groups,
236eadff302SIvan T. Ivanov 					 unsigned *const num_qgroups)
237eadff302SIvan T. Ivanov {
238eadff302SIvan T. Ivanov 	*groups = pmic_gpio_groups;
239eadff302SIvan T. Ivanov 	*num_qgroups = pctldev->desc->npins;
240eadff302SIvan T. Ivanov 	return 0;
241eadff302SIvan T. Ivanov }
242eadff302SIvan T. Ivanov 
243eadff302SIvan T. Ivanov static int pmic_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned function,
244eadff302SIvan T. Ivanov 				unsigned pin)
245eadff302SIvan T. Ivanov {
246eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev);
247eadff302SIvan T. Ivanov 	struct pmic_gpio_pad *pad;
248eadff302SIvan T. Ivanov 	unsigned int val;
249eadff302SIvan T. Ivanov 	int ret;
250eadff302SIvan T. Ivanov 
251eadff302SIvan T. Ivanov 	pad = pctldev->desc->pins[pin].drv_data;
252eadff302SIvan T. Ivanov 
253eadff302SIvan T. Ivanov 	pad->function = function;
254eadff302SIvan T. Ivanov 
255eadff302SIvan T. Ivanov 	val = 0;
256eadff302SIvan T. Ivanov 	if (pad->output_enabled) {
257eadff302SIvan T. Ivanov 		if (pad->input_enabled)
258eadff302SIvan T. Ivanov 			val = 2;
259eadff302SIvan T. Ivanov 		else
260eadff302SIvan T. Ivanov 			val = 1;
261eadff302SIvan T. Ivanov 	}
262eadff302SIvan T. Ivanov 
263eadff302SIvan T. Ivanov 	val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT;
264eadff302SIvan T. Ivanov 	val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT;
265eadff302SIvan T. Ivanov 
266eadff302SIvan T. Ivanov 	ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val);
267eadff302SIvan T. Ivanov 	if (ret < 0)
268eadff302SIvan T. Ivanov 		return ret;
269eadff302SIvan T. Ivanov 
270eadff302SIvan T. Ivanov 	val = pad->is_enabled << PMIC_GPIO_REG_MASTER_EN_SHIFT;
271eadff302SIvan T. Ivanov 
272eadff302SIvan T. Ivanov 	return pmic_gpio_write(state, pad, PMIC_GPIO_REG_EN_CTL, val);
273eadff302SIvan T. Ivanov }
274eadff302SIvan T. Ivanov 
275eadff302SIvan T. Ivanov static const struct pinmux_ops pmic_gpio_pinmux_ops = {
276eadff302SIvan T. Ivanov 	.get_functions_count	= pmic_gpio_get_functions_count,
277eadff302SIvan T. Ivanov 	.get_function_name	= pmic_gpio_get_function_name,
278eadff302SIvan T. Ivanov 	.get_function_groups	= pmic_gpio_get_function_groups,
279eadff302SIvan T. Ivanov 	.set_mux		= pmic_gpio_set_mux,
280eadff302SIvan T. Ivanov };
281eadff302SIvan T. Ivanov 
282eadff302SIvan T. Ivanov static int pmic_gpio_config_get(struct pinctrl_dev *pctldev,
283eadff302SIvan T. Ivanov 				unsigned int pin, unsigned long *config)
284eadff302SIvan T. Ivanov {
285eadff302SIvan T. Ivanov 	unsigned param = pinconf_to_config_param(*config);
286eadff302SIvan T. Ivanov 	struct pmic_gpio_pad *pad;
287eadff302SIvan T. Ivanov 	unsigned arg;
288eadff302SIvan T. Ivanov 
289eadff302SIvan T. Ivanov 	pad = pctldev->desc->pins[pin].drv_data;
290eadff302SIvan T. Ivanov 
291eadff302SIvan T. Ivanov 	switch (param) {
292eadff302SIvan T. Ivanov 	case PIN_CONFIG_DRIVE_PUSH_PULL:
293eadff302SIvan T. Ivanov 		arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_CMOS;
294eadff302SIvan T. Ivanov 		break;
295eadff302SIvan T. Ivanov 	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
296eadff302SIvan T. Ivanov 		arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS;
297eadff302SIvan T. Ivanov 		break;
298eadff302SIvan T. Ivanov 	case PIN_CONFIG_DRIVE_OPEN_SOURCE:
299eadff302SIvan T. Ivanov 		arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS;
300eadff302SIvan T. Ivanov 		break;
301eadff302SIvan T. Ivanov 	case PIN_CONFIG_BIAS_PULL_DOWN:
302eadff302SIvan T. Ivanov 		arg = pad->pullup == PMIC_GPIO_PULL_DOWN;
303eadff302SIvan T. Ivanov 		break;
304eadff302SIvan T. Ivanov 	case PIN_CONFIG_BIAS_DISABLE:
305eadff302SIvan T. Ivanov 		arg = pad->pullup = PMIC_GPIO_PULL_DISABLE;
306eadff302SIvan T. Ivanov 		break;
307eadff302SIvan T. Ivanov 	case PIN_CONFIG_BIAS_PULL_UP:
308eadff302SIvan T. Ivanov 		arg = pad->pullup == PMIC_GPIO_PULL_UP_30;
309eadff302SIvan T. Ivanov 		break;
310eadff302SIvan T. Ivanov 	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
311eadff302SIvan T. Ivanov 		arg = !pad->is_enabled;
312eadff302SIvan T. Ivanov 		break;
313eadff302SIvan T. Ivanov 	case PIN_CONFIG_POWER_SOURCE:
314eadff302SIvan T. Ivanov 		arg = pad->power_source;
315eadff302SIvan T. Ivanov 		break;
316eadff302SIvan T. Ivanov 	case PIN_CONFIG_INPUT_ENABLE:
317eadff302SIvan T. Ivanov 		arg = pad->input_enabled;
318eadff302SIvan T. Ivanov 		break;
319eadff302SIvan T. Ivanov 	case PIN_CONFIG_OUTPUT:
320eadff302SIvan T. Ivanov 		arg = pad->out_value;
321eadff302SIvan T. Ivanov 		break;
322eadff302SIvan T. Ivanov 	case PMIC_GPIO_CONF_PULL_UP:
323eadff302SIvan T. Ivanov 		arg = pad->pullup;
324eadff302SIvan T. Ivanov 		break;
325eadff302SIvan T. Ivanov 	case PMIC_GPIO_CONF_STRENGTH:
326eadff302SIvan T. Ivanov 		arg = pad->strength;
327eadff302SIvan T. Ivanov 		break;
328eadff302SIvan T. Ivanov 	default:
329eadff302SIvan T. Ivanov 		return -EINVAL;
330eadff302SIvan T. Ivanov 	}
331eadff302SIvan T. Ivanov 
332eadff302SIvan T. Ivanov 	*config = pinconf_to_config_packed(param, arg);
333eadff302SIvan T. Ivanov 	return 0;
334eadff302SIvan T. Ivanov }
335eadff302SIvan T. Ivanov 
336eadff302SIvan T. Ivanov static int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
337eadff302SIvan T. Ivanov 				unsigned long *configs, unsigned nconfs)
338eadff302SIvan T. Ivanov {
339eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev);
340eadff302SIvan T. Ivanov 	struct pmic_gpio_pad *pad;
341eadff302SIvan T. Ivanov 	unsigned param, arg;
342eadff302SIvan T. Ivanov 	unsigned int val;
343eadff302SIvan T. Ivanov 	int i, ret;
344eadff302SIvan T. Ivanov 
345eadff302SIvan T. Ivanov 	pad = pctldev->desc->pins[pin].drv_data;
346eadff302SIvan T. Ivanov 
347eadff302SIvan T. Ivanov 	for (i = 0; i < nconfs; i++) {
348eadff302SIvan T. Ivanov 		param = pinconf_to_config_param(configs[i]);
349eadff302SIvan T. Ivanov 		arg = pinconf_to_config_argument(configs[i]);
350eadff302SIvan T. Ivanov 
351eadff302SIvan T. Ivanov 		switch (param) {
352eadff302SIvan T. Ivanov 		case PIN_CONFIG_DRIVE_PUSH_PULL:
353eadff302SIvan T. Ivanov 			pad->buffer_type = PMIC_GPIO_OUT_BUF_CMOS;
354eadff302SIvan T. Ivanov 			break;
355eadff302SIvan T. Ivanov 		case PIN_CONFIG_DRIVE_OPEN_DRAIN:
356eadff302SIvan T. Ivanov 			if (!pad->have_buffer)
357eadff302SIvan T. Ivanov 				return -EINVAL;
358eadff302SIvan T. Ivanov 			pad->buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS;
359eadff302SIvan T. Ivanov 			break;
360eadff302SIvan T. Ivanov 		case PIN_CONFIG_DRIVE_OPEN_SOURCE:
361eadff302SIvan T. Ivanov 			if (!pad->have_buffer)
362eadff302SIvan T. Ivanov 				return -EINVAL;
363eadff302SIvan T. Ivanov 			pad->buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS;
364eadff302SIvan T. Ivanov 			break;
365eadff302SIvan T. Ivanov 		case PIN_CONFIG_BIAS_DISABLE:
366eadff302SIvan T. Ivanov 			pad->pullup = PMIC_GPIO_PULL_DISABLE;
367eadff302SIvan T. Ivanov 			break;
368eadff302SIvan T. Ivanov 		case PIN_CONFIG_BIAS_PULL_UP:
369eadff302SIvan T. Ivanov 			pad->pullup = PMIC_GPIO_PULL_UP_30;
370eadff302SIvan T. Ivanov 			break;
371eadff302SIvan T. Ivanov 		case PIN_CONFIG_BIAS_PULL_DOWN:
372eadff302SIvan T. Ivanov 			if (arg)
373eadff302SIvan T. Ivanov 				pad->pullup = PMIC_GPIO_PULL_DOWN;
374eadff302SIvan T. Ivanov 			else
375eadff302SIvan T. Ivanov 				pad->pullup = PMIC_GPIO_PULL_DISABLE;
376eadff302SIvan T. Ivanov 			break;
377eadff302SIvan T. Ivanov 		case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
378eadff302SIvan T. Ivanov 			pad->is_enabled = false;
379eadff302SIvan T. Ivanov 			break;
380eadff302SIvan T. Ivanov 		case PIN_CONFIG_POWER_SOURCE:
381eadff302SIvan T. Ivanov 			if (arg > pad->num_sources)
382eadff302SIvan T. Ivanov 				return -EINVAL;
383eadff302SIvan T. Ivanov 			pad->power_source = arg;
384eadff302SIvan T. Ivanov 			break;
385eadff302SIvan T. Ivanov 		case PIN_CONFIG_INPUT_ENABLE:
386eadff302SIvan T. Ivanov 			pad->input_enabled = arg ? true : false;
387eadff302SIvan T. Ivanov 			break;
388eadff302SIvan T. Ivanov 		case PIN_CONFIG_OUTPUT:
389eadff302SIvan T. Ivanov 			pad->output_enabled = true;
390eadff302SIvan T. Ivanov 			pad->out_value = arg;
391eadff302SIvan T. Ivanov 			break;
392eadff302SIvan T. Ivanov 		case PMIC_GPIO_CONF_PULL_UP:
393eadff302SIvan T. Ivanov 			if (arg > PMIC_GPIO_PULL_UP_1P5_30)
394eadff302SIvan T. Ivanov 				return -EINVAL;
395eadff302SIvan T. Ivanov 			pad->pullup = arg;
396eadff302SIvan T. Ivanov 			break;
397eadff302SIvan T. Ivanov 		case PMIC_GPIO_CONF_STRENGTH:
398eadff302SIvan T. Ivanov 			if (arg > PMIC_GPIO_STRENGTH_LOW)
399eadff302SIvan T. Ivanov 				return -EINVAL;
400eadff302SIvan T. Ivanov 			pad->strength = arg;
401eadff302SIvan T. Ivanov 			break;
402eadff302SIvan T. Ivanov 		default:
403eadff302SIvan T. Ivanov 			return -EINVAL;
404eadff302SIvan T. Ivanov 		}
405eadff302SIvan T. Ivanov 	}
406eadff302SIvan T. Ivanov 
407eadff302SIvan T. Ivanov 	val = pad->power_source << PMIC_GPIO_REG_VIN_SHIFT;
408eadff302SIvan T. Ivanov 
409eadff302SIvan T. Ivanov 	ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL, val);
410eadff302SIvan T. Ivanov 	if (ret < 0)
411eadff302SIvan T. Ivanov 		return ret;
412eadff302SIvan T. Ivanov 
413eadff302SIvan T. Ivanov 	val = pad->pullup << PMIC_GPIO_REG_PULL_SHIFT;
414eadff302SIvan T. Ivanov 
415eadff302SIvan T. Ivanov 	ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_PULL_CTL, val);
416eadff302SIvan T. Ivanov 	if (ret < 0)
417eadff302SIvan T. Ivanov 		return ret;
418eadff302SIvan T. Ivanov 
419eadff302SIvan T. Ivanov 	val = pad->buffer_type << PMIC_GPIO_REG_OUT_TYPE_SHIFT;
420eadff302SIvan T. Ivanov 	val = pad->strength << PMIC_GPIO_REG_OUT_STRENGTH_SHIFT;
421eadff302SIvan T. Ivanov 
422eadff302SIvan T. Ivanov 	ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL, val);
423eadff302SIvan T. Ivanov 	if (ret < 0)
424eadff302SIvan T. Ivanov 		return ret;
425eadff302SIvan T. Ivanov 
426eadff302SIvan T. Ivanov 	val = 0;
427eadff302SIvan T. Ivanov 	if (pad->output_enabled) {
428eadff302SIvan T. Ivanov 		if (pad->input_enabled)
429eadff302SIvan T. Ivanov 			val = 2;
430eadff302SIvan T. Ivanov 		else
431eadff302SIvan T. Ivanov 			val = 1;
432eadff302SIvan T. Ivanov 	}
433eadff302SIvan T. Ivanov 
434eadff302SIvan T. Ivanov 	val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT;
435eadff302SIvan T. Ivanov 	val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT;
436eadff302SIvan T. Ivanov 	val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT;
437eadff302SIvan T. Ivanov 
438eadff302SIvan T. Ivanov 	return pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val);
439eadff302SIvan T. Ivanov }
440eadff302SIvan T. Ivanov 
441eadff302SIvan T. Ivanov static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev,
442eadff302SIvan T. Ivanov 				      struct seq_file *s, unsigned pin)
443eadff302SIvan T. Ivanov {
444eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev);
445eadff302SIvan T. Ivanov 	struct pmic_gpio_pad *pad;
446eadff302SIvan T. Ivanov 	int ret, val;
447eadff302SIvan T. Ivanov 
448eadff302SIvan T. Ivanov 	static const char *const biases[] = {
449eadff302SIvan T. Ivanov 		"pull-up 30uA", "pull-up 1.5uA", "pull-up 31.5uA",
450eadff302SIvan T. Ivanov 		"pull-up 1.5uA + 30uA boost", "pull-down 10uA", "no pull"
451eadff302SIvan T. Ivanov 	};
452eadff302SIvan T. Ivanov 	static const char *const buffer_types[] = {
453eadff302SIvan T. Ivanov 		"push-pull", "open-drain", "open-source"
454eadff302SIvan T. Ivanov 	};
455eadff302SIvan T. Ivanov 	static const char *const strengths[] = {
456eadff302SIvan T. Ivanov 		"no", "high", "medium", "low"
457eadff302SIvan T. Ivanov 	};
458eadff302SIvan T. Ivanov 
459eadff302SIvan T. Ivanov 	pad = pctldev->desc->pins[pin].drv_data;
460eadff302SIvan T. Ivanov 
461eadff302SIvan T. Ivanov 	seq_printf(s, " gpio%-2d:", pin + PMIC_GPIO_PHYSICAL_OFFSET);
462eadff302SIvan T. Ivanov 
463eadff302SIvan T. Ivanov 	val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_EN_CTL);
464eadff302SIvan T. Ivanov 
465eadff302SIvan T. Ivanov 	if (val < 0 || !(val >> PMIC_GPIO_REG_MASTER_EN_SHIFT)) {
466eadff302SIvan T. Ivanov 		seq_puts(s, " ---");
467eadff302SIvan T. Ivanov 	} else {
468eadff302SIvan T. Ivanov 
469eadff302SIvan T. Ivanov 		if (!pad->input_enabled) {
470eadff302SIvan T. Ivanov 			ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS);
471eadff302SIvan T. Ivanov 			if (!ret) {
472eadff302SIvan T. Ivanov 				ret &= PMIC_MPP_REG_RT_STS_VAL_MASK;
473eadff302SIvan T. Ivanov 				pad->out_value = ret;
474eadff302SIvan T. Ivanov 			}
475eadff302SIvan T. Ivanov 		}
476eadff302SIvan T. Ivanov 
477eadff302SIvan T. Ivanov 		seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in");
478eadff302SIvan T. Ivanov 		seq_printf(s, " %-7s", pmic_gpio_functions[pad->function]);
479eadff302SIvan T. Ivanov 		seq_printf(s, " vin-%d", pad->power_source);
480eadff302SIvan T. Ivanov 		seq_printf(s, " %-27s", biases[pad->pullup]);
481eadff302SIvan T. Ivanov 		seq_printf(s, " %-10s", buffer_types[pad->buffer_type]);
482eadff302SIvan T. Ivanov 		seq_printf(s, " %-4s", pad->out_value ? "high" : "low");
483eadff302SIvan T. Ivanov 		seq_printf(s, " %-7s", strengths[pad->strength]);
484eadff302SIvan T. Ivanov 	}
485eadff302SIvan T. Ivanov }
486eadff302SIvan T. Ivanov 
487eadff302SIvan T. Ivanov static const struct pinconf_ops pmic_gpio_pinconf_ops = {
4887382b623SSoren Brinkmann 	.is_generic			= true,
489eadff302SIvan T. Ivanov 	.pin_config_group_get		= pmic_gpio_config_get,
490eadff302SIvan T. Ivanov 	.pin_config_group_set		= pmic_gpio_config_set,
491eadff302SIvan T. Ivanov 	.pin_config_group_dbg_show	= pmic_gpio_config_dbg_show,
492eadff302SIvan T. Ivanov };
493eadff302SIvan T. Ivanov 
494eadff302SIvan T. Ivanov static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
495eadff302SIvan T. Ivanov {
496eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state = to_gpio_state(chip);
497eadff302SIvan T. Ivanov 	unsigned long config;
498eadff302SIvan T. Ivanov 
499eadff302SIvan T. Ivanov 	config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
500eadff302SIvan T. Ivanov 
501eadff302SIvan T. Ivanov 	return pmic_gpio_config_set(state->ctrl, pin, &config, 1);
502eadff302SIvan T. Ivanov }
503eadff302SIvan T. Ivanov 
504eadff302SIvan T. Ivanov static int pmic_gpio_direction_output(struct gpio_chip *chip,
505eadff302SIvan T. Ivanov 				      unsigned pin, int val)
506eadff302SIvan T. Ivanov {
507eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state = to_gpio_state(chip);
508eadff302SIvan T. Ivanov 	unsigned long config;
509eadff302SIvan T. Ivanov 
510eadff302SIvan T. Ivanov 	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
511eadff302SIvan T. Ivanov 
512eadff302SIvan T. Ivanov 	return pmic_gpio_config_set(state->ctrl, pin, &config, 1);
513eadff302SIvan T. Ivanov }
514eadff302SIvan T. Ivanov 
515eadff302SIvan T. Ivanov static int pmic_gpio_get(struct gpio_chip *chip, unsigned pin)
516eadff302SIvan T. Ivanov {
517eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state = to_gpio_state(chip);
518eadff302SIvan T. Ivanov 	struct pmic_gpio_pad *pad;
519eadff302SIvan T. Ivanov 	int ret;
520eadff302SIvan T. Ivanov 
521eadff302SIvan T. Ivanov 	pad = state->ctrl->desc->pins[pin].drv_data;
522eadff302SIvan T. Ivanov 
523eadff302SIvan T. Ivanov 	if (!pad->is_enabled)
524eadff302SIvan T. Ivanov 		return -EINVAL;
525eadff302SIvan T. Ivanov 
526eadff302SIvan T. Ivanov 	if (pad->input_enabled) {
527eadff302SIvan T. Ivanov 		ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS);
528eadff302SIvan T. Ivanov 		if (ret < 0)
529eadff302SIvan T. Ivanov 			return ret;
530eadff302SIvan T. Ivanov 
531eadff302SIvan T. Ivanov 		pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK;
532eadff302SIvan T. Ivanov 	}
533eadff302SIvan T. Ivanov 
534eadff302SIvan T. Ivanov 	return pad->out_value;
535eadff302SIvan T. Ivanov }
536eadff302SIvan T. Ivanov 
537eadff302SIvan T. Ivanov static void pmic_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
538eadff302SIvan T. Ivanov {
539eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state = to_gpio_state(chip);
540eadff302SIvan T. Ivanov 	unsigned long config;
541eadff302SIvan T. Ivanov 
542eadff302SIvan T. Ivanov 	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
543eadff302SIvan T. Ivanov 
544eadff302SIvan T. Ivanov 	pmic_gpio_config_set(state->ctrl, pin, &config, 1);
545eadff302SIvan T. Ivanov }
546eadff302SIvan T. Ivanov 
547eadff302SIvan T. Ivanov static int pmic_gpio_request(struct gpio_chip *chip, unsigned base)
548eadff302SIvan T. Ivanov {
549eadff302SIvan T. Ivanov 	return pinctrl_request_gpio(chip->base + base);
550eadff302SIvan T. Ivanov }
551eadff302SIvan T. Ivanov 
552eadff302SIvan T. Ivanov static void pmic_gpio_free(struct gpio_chip *chip, unsigned base)
553eadff302SIvan T. Ivanov {
554eadff302SIvan T. Ivanov 	pinctrl_free_gpio(chip->base + base);
555eadff302SIvan T. Ivanov }
556eadff302SIvan T. Ivanov 
557eadff302SIvan T. Ivanov static int pmic_gpio_of_xlate(struct gpio_chip *chip,
558eadff302SIvan T. Ivanov 			      const struct of_phandle_args *gpio_desc,
559eadff302SIvan T. Ivanov 			      u32 *flags)
560eadff302SIvan T. Ivanov {
561eadff302SIvan T. Ivanov 	if (chip->of_gpio_n_cells < 2)
562eadff302SIvan T. Ivanov 		return -EINVAL;
563eadff302SIvan T. Ivanov 
564eadff302SIvan T. Ivanov 	if (flags)
565eadff302SIvan T. Ivanov 		*flags = gpio_desc->args[1];
566eadff302SIvan T. Ivanov 
567eadff302SIvan T. Ivanov 	return gpio_desc->args[0] - PMIC_GPIO_PHYSICAL_OFFSET;
568eadff302SIvan T. Ivanov }
569eadff302SIvan T. Ivanov 
570eadff302SIvan T. Ivanov static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
571eadff302SIvan T. Ivanov {
572eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state = to_gpio_state(chip);
573eadff302SIvan T. Ivanov 	struct pmic_gpio_pad *pad;
574eadff302SIvan T. Ivanov 
575eadff302SIvan T. Ivanov 	pad = state->ctrl->desc->pins[pin].drv_data;
576eadff302SIvan T. Ivanov 
577eadff302SIvan T. Ivanov 	return pad->irq;
578eadff302SIvan T. Ivanov }
579eadff302SIvan T. Ivanov 
580eadff302SIvan T. Ivanov static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
581eadff302SIvan T. Ivanov {
582eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state = to_gpio_state(chip);
583eadff302SIvan T. Ivanov 	unsigned i;
584eadff302SIvan T. Ivanov 
585eadff302SIvan T. Ivanov 	for (i = 0; i < chip->ngpio; i++) {
586eadff302SIvan T. Ivanov 		pmic_gpio_config_dbg_show(state->ctrl, s, i);
587eadff302SIvan T. Ivanov 		seq_puts(s, "\n");
588eadff302SIvan T. Ivanov 	}
589eadff302SIvan T. Ivanov }
590eadff302SIvan T. Ivanov 
591eadff302SIvan T. Ivanov static const struct gpio_chip pmic_gpio_gpio_template = {
592eadff302SIvan T. Ivanov 	.direction_input	= pmic_gpio_direction_input,
593eadff302SIvan T. Ivanov 	.direction_output	= pmic_gpio_direction_output,
594eadff302SIvan T. Ivanov 	.get			= pmic_gpio_get,
595eadff302SIvan T. Ivanov 	.set			= pmic_gpio_set,
596eadff302SIvan T. Ivanov 	.request		= pmic_gpio_request,
597eadff302SIvan T. Ivanov 	.free			= pmic_gpio_free,
598eadff302SIvan T. Ivanov 	.of_xlate		= pmic_gpio_of_xlate,
599eadff302SIvan T. Ivanov 	.to_irq			= pmic_gpio_to_irq,
600eadff302SIvan T. Ivanov 	.dbg_show		= pmic_gpio_dbg_show,
601eadff302SIvan T. Ivanov };
602eadff302SIvan T. Ivanov 
603eadff302SIvan T. Ivanov static int pmic_gpio_populate(struct pmic_gpio_state *state,
604eadff302SIvan T. Ivanov 			      struct pmic_gpio_pad *pad)
605eadff302SIvan T. Ivanov {
606eadff302SIvan T. Ivanov 	int type, subtype, val, dir;
607eadff302SIvan T. Ivanov 
608eadff302SIvan T. Ivanov 	type = pmic_gpio_read(state, pad, PMIC_GPIO_REG_TYPE);
609eadff302SIvan T. Ivanov 	if (type < 0)
610eadff302SIvan T. Ivanov 		return type;
611eadff302SIvan T. Ivanov 
612eadff302SIvan T. Ivanov 	if (type != PMIC_GPIO_TYPE) {
613eadff302SIvan T. Ivanov 		dev_err(state->dev, "incorrect block type 0x%x at 0x%x\n",
614eadff302SIvan T. Ivanov 			type, pad->base);
615eadff302SIvan T. Ivanov 		return -ENODEV;
616eadff302SIvan T. Ivanov 	}
617eadff302SIvan T. Ivanov 
618eadff302SIvan T. Ivanov 	subtype = pmic_gpio_read(state, pad, PMIC_GPIO_REG_SUBTYPE);
619eadff302SIvan T. Ivanov 	if (subtype < 0)
620eadff302SIvan T. Ivanov 		return subtype;
621eadff302SIvan T. Ivanov 
622eadff302SIvan T. Ivanov 	switch (subtype) {
623eadff302SIvan T. Ivanov 	case PMIC_GPIO_SUBTYPE_GPIO_4CH:
624eadff302SIvan T. Ivanov 		pad->have_buffer = true;
625eadff302SIvan T. Ivanov 	case PMIC_GPIO_SUBTYPE_GPIOC_4CH:
626eadff302SIvan T. Ivanov 		pad->num_sources = 4;
627eadff302SIvan T. Ivanov 		break;
628eadff302SIvan T. Ivanov 	case PMIC_GPIO_SUBTYPE_GPIO_8CH:
629eadff302SIvan T. Ivanov 		pad->have_buffer = true;
630eadff302SIvan T. Ivanov 	case PMIC_GPIO_SUBTYPE_GPIOC_8CH:
631eadff302SIvan T. Ivanov 		pad->num_sources = 8;
632eadff302SIvan T. Ivanov 		break;
633eadff302SIvan T. Ivanov 	default:
634eadff302SIvan T. Ivanov 		dev_err(state->dev, "unknown GPIO type 0x%x\n", subtype);
635eadff302SIvan T. Ivanov 		return -ENODEV;
636eadff302SIvan T. Ivanov 	}
637eadff302SIvan T. Ivanov 
638eadff302SIvan T. Ivanov 	val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL);
639eadff302SIvan T. Ivanov 	if (val < 0)
640eadff302SIvan T. Ivanov 		return val;
641eadff302SIvan T. Ivanov 
642eadff302SIvan T. Ivanov 	pad->out_value = val & PMIC_GPIO_REG_MODE_VALUE_SHIFT;
643eadff302SIvan T. Ivanov 
644eadff302SIvan T. Ivanov 	dir = val >> PMIC_GPIO_REG_MODE_DIR_SHIFT;
645eadff302SIvan T. Ivanov 	dir &= PMIC_GPIO_REG_MODE_DIR_MASK;
646eadff302SIvan T. Ivanov 	switch (dir) {
647eadff302SIvan T. Ivanov 	case 0:
648eadff302SIvan T. Ivanov 		pad->input_enabled = true;
649eadff302SIvan T. Ivanov 		pad->output_enabled = false;
650eadff302SIvan T. Ivanov 		break;
651eadff302SIvan T. Ivanov 	case 1:
652eadff302SIvan T. Ivanov 		pad->input_enabled = false;
653eadff302SIvan T. Ivanov 		pad->output_enabled = true;
654eadff302SIvan T. Ivanov 		break;
655eadff302SIvan T. Ivanov 	case 2:
656eadff302SIvan T. Ivanov 		pad->input_enabled = true;
657eadff302SIvan T. Ivanov 		pad->output_enabled = true;
658eadff302SIvan T. Ivanov 		break;
659eadff302SIvan T. Ivanov 	default:
660eadff302SIvan T. Ivanov 		dev_err(state->dev, "unknown GPIO direction\n");
661eadff302SIvan T. Ivanov 		return -ENODEV;
662eadff302SIvan T. Ivanov 	}
663eadff302SIvan T. Ivanov 
664eadff302SIvan T. Ivanov 	pad->function = val >> PMIC_GPIO_REG_MODE_FUNCTION_SHIFT;
665eadff302SIvan T. Ivanov 	pad->function &= PMIC_GPIO_REG_MODE_FUNCTION_MASK;
666eadff302SIvan T. Ivanov 
667eadff302SIvan T. Ivanov 	val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL);
668eadff302SIvan T. Ivanov 	if (val < 0)
669eadff302SIvan T. Ivanov 		return val;
670eadff302SIvan T. Ivanov 
671eadff302SIvan T. Ivanov 	pad->power_source = val >> PMIC_GPIO_REG_VIN_SHIFT;
672eadff302SIvan T. Ivanov 	pad->power_source &= PMIC_GPIO_REG_VIN_MASK;
673eadff302SIvan T. Ivanov 
674eadff302SIvan T. Ivanov 	val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_PULL_CTL);
675eadff302SIvan T. Ivanov 	if (val < 0)
676eadff302SIvan T. Ivanov 		return val;
677eadff302SIvan T. Ivanov 
678eadff302SIvan T. Ivanov 	pad->pullup = val >> PMIC_GPIO_REG_PULL_SHIFT;
679eadff302SIvan T. Ivanov 	pad->pullup &= PMIC_GPIO_REG_PULL_MASK;
680eadff302SIvan T. Ivanov 
681eadff302SIvan T. Ivanov 	val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL);
682eadff302SIvan T. Ivanov 	if (val < 0)
683eadff302SIvan T. Ivanov 		return val;
684eadff302SIvan T. Ivanov 
685eadff302SIvan T. Ivanov 	pad->strength = val >> PMIC_GPIO_REG_OUT_STRENGTH_SHIFT;
686eadff302SIvan T. Ivanov 	pad->strength &= PMIC_GPIO_REG_OUT_STRENGTH_MASK;
687eadff302SIvan T. Ivanov 
688eadff302SIvan T. Ivanov 	pad->buffer_type = val >> PMIC_GPIO_REG_OUT_TYPE_SHIFT;
689eadff302SIvan T. Ivanov 	pad->buffer_type &= PMIC_GPIO_REG_OUT_TYPE_MASK;
690eadff302SIvan T. Ivanov 
691eadff302SIvan T. Ivanov 	/* Pin could be disabled with PIN_CONFIG_BIAS_HIGH_IMPEDANCE */
692eadff302SIvan T. Ivanov 	pad->is_enabled = true;
693eadff302SIvan T. Ivanov 	return 0;
694eadff302SIvan T. Ivanov }
695eadff302SIvan T. Ivanov 
696eadff302SIvan T. Ivanov static int pmic_gpio_probe(struct platform_device *pdev)
697eadff302SIvan T. Ivanov {
698eadff302SIvan T. Ivanov 	struct device *dev = &pdev->dev;
699eadff302SIvan T. Ivanov 	struct pinctrl_pin_desc *pindesc;
700eadff302SIvan T. Ivanov 	struct pinctrl_desc *pctrldesc;
701eadff302SIvan T. Ivanov 	struct pmic_gpio_pad *pad, *pads;
702eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state;
703eadff302SIvan T. Ivanov 	int ret, npins, i;
704eadff302SIvan T. Ivanov 	u32 res[2];
705eadff302SIvan T. Ivanov 
706eadff302SIvan T. Ivanov 	ret = of_property_read_u32_array(dev->of_node, "reg", res, 2);
707eadff302SIvan T. Ivanov 	if (ret < 0) {
708eadff302SIvan T. Ivanov 		dev_err(dev, "missing base address and/or range");
709eadff302SIvan T. Ivanov 		return ret;
710eadff302SIvan T. Ivanov 	}
711eadff302SIvan T. Ivanov 
712eadff302SIvan T. Ivanov 	npins = res[1] / PMIC_GPIO_ADDRESS_RANGE;
713eadff302SIvan T. Ivanov 
714eadff302SIvan T. Ivanov 	if (!npins)
715eadff302SIvan T. Ivanov 		return -EINVAL;
716eadff302SIvan T. Ivanov 
717eadff302SIvan T. Ivanov 	BUG_ON(npins > ARRAY_SIZE(pmic_gpio_groups));
718eadff302SIvan T. Ivanov 
719eadff302SIvan T. Ivanov 	state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
720eadff302SIvan T. Ivanov 	if (!state)
721eadff302SIvan T. Ivanov 		return -ENOMEM;
722eadff302SIvan T. Ivanov 
723eadff302SIvan T. Ivanov 	platform_set_drvdata(pdev, state);
724eadff302SIvan T. Ivanov 
725eadff302SIvan T. Ivanov 	state->dev = &pdev->dev;
726eadff302SIvan T. Ivanov 	state->map = dev_get_regmap(dev->parent, NULL);
727eadff302SIvan T. Ivanov 
728eadff302SIvan T. Ivanov 	pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
729eadff302SIvan T. Ivanov 	if (!pindesc)
730eadff302SIvan T. Ivanov 		return -ENOMEM;
731eadff302SIvan T. Ivanov 
732eadff302SIvan T. Ivanov 	pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL);
733eadff302SIvan T. Ivanov 	if (!pads)
734eadff302SIvan T. Ivanov 		return -ENOMEM;
735eadff302SIvan T. Ivanov 
736eadff302SIvan T. Ivanov 	pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL);
737eadff302SIvan T. Ivanov 	if (!pctrldesc)
738eadff302SIvan T. Ivanov 		return -ENOMEM;
739eadff302SIvan T. Ivanov 
740eadff302SIvan T. Ivanov 	pctrldesc->pctlops = &pmic_gpio_pinctrl_ops;
741eadff302SIvan T. Ivanov 	pctrldesc->pmxops = &pmic_gpio_pinmux_ops;
742eadff302SIvan T. Ivanov 	pctrldesc->confops = &pmic_gpio_pinconf_ops;
743eadff302SIvan T. Ivanov 	pctrldesc->owner = THIS_MODULE;
744eadff302SIvan T. Ivanov 	pctrldesc->name = dev_name(dev);
745eadff302SIvan T. Ivanov 	pctrldesc->pins = pindesc;
746eadff302SIvan T. Ivanov 	pctrldesc->npins = npins;
747f684e4acSLinus Walleij 	pctrldesc->num_custom_params = ARRAY_SIZE(pmic_gpio_bindings);
748f684e4acSLinus Walleij 	pctrldesc->custom_params = pmic_gpio_bindings;
7494f06266aSArnd Bergmann #ifdef CONFIG_DEBUG_FS
750f684e4acSLinus Walleij 	pctrldesc->custom_conf_items = pmic_conf_items;
7514f06266aSArnd Bergmann #endif
752eadff302SIvan T. Ivanov 
753eadff302SIvan T. Ivanov 	for (i = 0; i < npins; i++, pindesc++) {
754eadff302SIvan T. Ivanov 		pad = &pads[i];
755eadff302SIvan T. Ivanov 		pindesc->drv_data = pad;
756eadff302SIvan T. Ivanov 		pindesc->number = i;
757eadff302SIvan T. Ivanov 		pindesc->name = pmic_gpio_groups[i];
758eadff302SIvan T. Ivanov 
759eadff302SIvan T. Ivanov 		pad->irq = platform_get_irq(pdev, i);
760eadff302SIvan T. Ivanov 		if (pad->irq < 0)
761eadff302SIvan T. Ivanov 			return pad->irq;
762eadff302SIvan T. Ivanov 
763eadff302SIvan T. Ivanov 		pad->base = res[0] + i * PMIC_GPIO_ADDRESS_RANGE;
764eadff302SIvan T. Ivanov 
765eadff302SIvan T. Ivanov 		ret = pmic_gpio_populate(state, pad);
766eadff302SIvan T. Ivanov 		if (ret < 0)
767eadff302SIvan T. Ivanov 			return ret;
768eadff302SIvan T. Ivanov 	}
769eadff302SIvan T. Ivanov 
770eadff302SIvan T. Ivanov 	state->chip = pmic_gpio_gpio_template;
771eadff302SIvan T. Ivanov 	state->chip.dev = dev;
772eadff302SIvan T. Ivanov 	state->chip.base = -1;
773eadff302SIvan T. Ivanov 	state->chip.ngpio = npins;
774eadff302SIvan T. Ivanov 	state->chip.label = dev_name(dev);
775eadff302SIvan T. Ivanov 	state->chip.of_gpio_n_cells = 2;
776eadff302SIvan T. Ivanov 	state->chip.can_sleep = false;
777eadff302SIvan T. Ivanov 
778eadff302SIvan T. Ivanov 	state->ctrl = pinctrl_register(pctrldesc, dev, state);
779eadff302SIvan T. Ivanov 	if (!state->ctrl)
780eadff302SIvan T. Ivanov 		return -ENODEV;
781eadff302SIvan T. Ivanov 
782eadff302SIvan T. Ivanov 	ret = gpiochip_add(&state->chip);
783eadff302SIvan T. Ivanov 	if (ret) {
784eadff302SIvan T. Ivanov 		dev_err(state->dev, "can't add gpio chip\n");
785eadff302SIvan T. Ivanov 		goto err_chip;
786eadff302SIvan T. Ivanov 	}
787eadff302SIvan T. Ivanov 
788eadff302SIvan T. Ivanov 	ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins);
789eadff302SIvan T. Ivanov 	if (ret) {
790eadff302SIvan T. Ivanov 		dev_err(dev, "failed to add pin range\n");
791eadff302SIvan T. Ivanov 		goto err_range;
792eadff302SIvan T. Ivanov 	}
793eadff302SIvan T. Ivanov 
794eadff302SIvan T. Ivanov 	return 0;
795eadff302SIvan T. Ivanov 
796eadff302SIvan T. Ivanov err_range:
797eadff302SIvan T. Ivanov 	gpiochip_remove(&state->chip);
798eadff302SIvan T. Ivanov err_chip:
799eadff302SIvan T. Ivanov 	pinctrl_unregister(state->ctrl);
800eadff302SIvan T. Ivanov 	return ret;
801eadff302SIvan T. Ivanov }
802eadff302SIvan T. Ivanov 
803eadff302SIvan T. Ivanov static int pmic_gpio_remove(struct platform_device *pdev)
804eadff302SIvan T. Ivanov {
805eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state = platform_get_drvdata(pdev);
806eadff302SIvan T. Ivanov 
807eadff302SIvan T. Ivanov 	gpiochip_remove(&state->chip);
808eadff302SIvan T. Ivanov 	pinctrl_unregister(state->ctrl);
809eadff302SIvan T. Ivanov 	return 0;
810eadff302SIvan T. Ivanov }
811eadff302SIvan T. Ivanov 
812eadff302SIvan T. Ivanov static const struct of_device_id pmic_gpio_of_match[] = {
813eadff302SIvan T. Ivanov 	{ .compatible = "qcom,pm8941-gpio" },	/* 36 GPIO's */
814eadff302SIvan T. Ivanov 	{ .compatible = "qcom,pma8084-gpio" },	/* 22 GPIO's */
815eadff302SIvan T. Ivanov 	{ },
816eadff302SIvan T. Ivanov };
817eadff302SIvan T. Ivanov 
818eadff302SIvan T. Ivanov MODULE_DEVICE_TABLE(of, pmic_gpio_of_match);
819eadff302SIvan T. Ivanov 
820eadff302SIvan T. Ivanov static struct platform_driver pmic_gpio_driver = {
821eadff302SIvan T. Ivanov 	.driver = {
822eadff302SIvan T. Ivanov 		   .name = "qcom-spmi-gpio",
823eadff302SIvan T. Ivanov 		   .of_match_table = pmic_gpio_of_match,
824eadff302SIvan T. Ivanov 	},
825eadff302SIvan T. Ivanov 	.probe	= pmic_gpio_probe,
826eadff302SIvan T. Ivanov 	.remove = pmic_gpio_remove,
827eadff302SIvan T. Ivanov };
828eadff302SIvan T. Ivanov 
829eadff302SIvan T. Ivanov module_platform_driver(pmic_gpio_driver);
830eadff302SIvan T. Ivanov 
831eadff302SIvan T. Ivanov MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
832eadff302SIvan T. Ivanov MODULE_DESCRIPTION("Qualcomm SPMI PMIC GPIO pin control driver");
833eadff302SIvan T. Ivanov MODULE_ALIAS("platform:qcom-spmi-gpio");
834eadff302SIvan T. Ivanov MODULE_LICENSE("GPL v2");
835