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 
141c5fb66aSLinus Walleij #include <linux/gpio/driver.h>
15eadff302SIvan T. Ivanov #include <linux/module.h>
16eadff302SIvan T. Ivanov #include <linux/of.h>
17ab4256cfSStephen Boyd #include <linux/of_irq.h>
18eadff302SIvan T. Ivanov #include <linux/pinctrl/pinconf-generic.h>
19eadff302SIvan T. Ivanov #include <linux/pinctrl/pinconf.h>
20eadff302SIvan T. Ivanov #include <linux/pinctrl/pinmux.h>
21eadff302SIvan T. Ivanov #include <linux/platform_device.h>
22eadff302SIvan T. Ivanov #include <linux/regmap.h>
23eadff302SIvan T. Ivanov #include <linux/slab.h>
24eadff302SIvan T. Ivanov #include <linux/types.h>
25eadff302SIvan T. Ivanov 
26eadff302SIvan T. Ivanov #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
27eadff302SIvan T. Ivanov 
28eadff302SIvan T. Ivanov #include "../core.h"
29eadff302SIvan T. Ivanov #include "../pinctrl-utils.h"
30eadff302SIvan T. Ivanov 
31eadff302SIvan T. Ivanov #define PMIC_GPIO_ADDRESS_RANGE			0x100
32eadff302SIvan T. Ivanov 
33eadff302SIvan T. Ivanov /* type and subtype registers base address offsets */
34eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_TYPE			0x4
35eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_SUBTYPE			0x5
36eadff302SIvan T. Ivanov 
37eadff302SIvan T. Ivanov /* GPIO peripheral type and subtype out_values */
38eadff302SIvan T. Ivanov #define PMIC_GPIO_TYPE				0x10
39eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIO_4CH		0x1
40eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIOC_4CH		0x5
41eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIO_8CH		0x9
42eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIOC_8CH		0xd
43d7b5f5ccSFenglin Wu #define PMIC_GPIO_SUBTYPE_GPIO_LV		0x10
44d7b5f5ccSFenglin Wu #define PMIC_GPIO_SUBTYPE_GPIO_MV		0x11
45eadff302SIvan T. Ivanov 
46eadff302SIvan T. Ivanov #define PMIC_MPP_REG_RT_STS			0x10
47eadff302SIvan T. Ivanov #define PMIC_MPP_REG_RT_STS_VAL_MASK		0x1
48eadff302SIvan T. Ivanov 
49eadff302SIvan T. Ivanov /* control register base address offsets */
50eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_CTL			0x40
51eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_DIG_VIN_CTL		0x41
52eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_DIG_PULL_CTL		0x42
53d7b5f5ccSFenglin Wu #define PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL	0x44
54223463fcSFenglin Wu #define PMIC_GPIO_REG_DIG_IN_CTL		0x43
55eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_DIG_OUT_CTL		0x45
56eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_EN_CTL			0x46
57d7b5f5ccSFenglin Wu #define PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL	0x4A
58eadff302SIvan T. Ivanov 
59eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_MODE_CTL */
60eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_VALUE_SHIFT		0x1
61eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_FUNCTION_SHIFT	1
62eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_FUNCTION_MASK	0x7
63eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_DIR_SHIFT		4
64eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_DIR_MASK		0x7
65eadff302SIvan T. Ivanov 
66d7b5f5ccSFenglin Wu #define PMIC_GPIO_MODE_DIGITAL_INPUT		0
67d7b5f5ccSFenglin Wu #define PMIC_GPIO_MODE_DIGITAL_OUTPUT		1
68d7b5f5ccSFenglin Wu #define PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT	2
69d7b5f5ccSFenglin Wu #define PMIC_GPIO_MODE_ANALOG_PASS_THRU		3
70d7b5f5ccSFenglin Wu #define PMIC_GPIO_REG_LV_MV_MODE_DIR_MASK	0x3
71d7b5f5ccSFenglin Wu 
72eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_DIG_VIN_CTL */
73eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_VIN_SHIFT			0
74eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_VIN_MASK			0x7
75eadff302SIvan T. Ivanov 
76eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_DIG_PULL_CTL */
77eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_PULL_SHIFT		0
78eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_PULL_MASK			0x7
79eadff302SIvan T. Ivanov 
80eadff302SIvan T. Ivanov #define PMIC_GPIO_PULL_DOWN			4
81eadff302SIvan T. Ivanov #define PMIC_GPIO_PULL_DISABLE			5
82eadff302SIvan T. Ivanov 
83d7b5f5ccSFenglin Wu /* PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL for LV/MV */
84d7b5f5ccSFenglin Wu #define PMIC_GPIO_LV_MV_OUTPUT_INVERT		0x80
85d7b5f5ccSFenglin Wu #define PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT	7
86d7b5f5ccSFenglin Wu #define PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK	0xF
87d7b5f5ccSFenglin Wu 
88223463fcSFenglin Wu /* PMIC_GPIO_REG_DIG_IN_CTL */
89223463fcSFenglin Wu #define PMIC_GPIO_LV_MV_DIG_IN_DTEST_EN		0x80
90223463fcSFenglin Wu #define PMIC_GPIO_LV_MV_DIG_IN_DTEST_SEL_MASK	0x7
91223463fcSFenglin Wu #define PMIC_GPIO_DIG_IN_DTEST_SEL_MASK		0xf
92223463fcSFenglin Wu 
93eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_DIG_OUT_CTL */
94eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_STRENGTH_SHIFT	0
95eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_STRENGTH_MASK		0x3
96eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_TYPE_SHIFT		4
97eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_TYPE_MASK		0x3
98eadff302SIvan T. Ivanov 
99eadff302SIvan T. Ivanov /*
100eadff302SIvan T. Ivanov  * Output type - indicates pin should be configured as push-pull,
101eadff302SIvan T. Ivanov  * open drain or open source.
102eadff302SIvan T. Ivanov  */
103eadff302SIvan T. Ivanov #define PMIC_GPIO_OUT_BUF_CMOS			0
104eadff302SIvan T. Ivanov #define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS	1
105eadff302SIvan T. Ivanov #define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS	2
106eadff302SIvan T. Ivanov 
107eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_EN_CTL */
108eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MASTER_EN_SHIFT		7
109eadff302SIvan T. Ivanov 
110eadff302SIvan T. Ivanov #define PMIC_GPIO_PHYSICAL_OFFSET		1
111eadff302SIvan T. Ivanov 
112d7b5f5ccSFenglin Wu /* PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL */
113d7b5f5ccSFenglin Wu #define PMIC_GPIO_LV_MV_ANA_MUX_SEL_MASK		0x3
114d7b5f5ccSFenglin Wu 
115eadff302SIvan T. Ivanov /* Qualcomm specific pin configurations */
116eadff302SIvan T. Ivanov #define PMIC_GPIO_CONF_PULL_UP			(PIN_CONFIG_END + 1)
117eadff302SIvan T. Ivanov #define PMIC_GPIO_CONF_STRENGTH			(PIN_CONFIG_END + 2)
118d7b5f5ccSFenglin Wu #define PMIC_GPIO_CONF_ATEST			(PIN_CONFIG_END + 3)
119d7b5f5ccSFenglin Wu #define PMIC_GPIO_CONF_ANALOG_PASS		(PIN_CONFIG_END + 4)
120223463fcSFenglin Wu #define PMIC_GPIO_CONF_DTEST_BUFFER		(PIN_CONFIG_END + 5)
121d7b5f5ccSFenglin Wu 
122d7b5f5ccSFenglin Wu /* The index of each function in pmic_gpio_functions[] array */
123d7b5f5ccSFenglin Wu enum pmic_gpio_func_index {
124d7b5f5ccSFenglin Wu 	PMIC_GPIO_FUNC_INDEX_NORMAL,
125d7b5f5ccSFenglin Wu 	PMIC_GPIO_FUNC_INDEX_PAIRED,
126d7b5f5ccSFenglin Wu 	PMIC_GPIO_FUNC_INDEX_FUNC1,
127d7b5f5ccSFenglin Wu 	PMIC_GPIO_FUNC_INDEX_FUNC2,
128d7b5f5ccSFenglin Wu 	PMIC_GPIO_FUNC_INDEX_FUNC3,
129d7b5f5ccSFenglin Wu 	PMIC_GPIO_FUNC_INDEX_FUNC4,
130d7b5f5ccSFenglin Wu 	PMIC_GPIO_FUNC_INDEX_DTEST1,
131d7b5f5ccSFenglin Wu 	PMIC_GPIO_FUNC_INDEX_DTEST2,
132d7b5f5ccSFenglin Wu 	PMIC_GPIO_FUNC_INDEX_DTEST3,
133d7b5f5ccSFenglin Wu 	PMIC_GPIO_FUNC_INDEX_DTEST4,
134d7b5f5ccSFenglin Wu };
135eadff302SIvan T. Ivanov 
136eadff302SIvan T. Ivanov /**
137eadff302SIvan T. Ivanov  * struct pmic_gpio_pad - keep current GPIO settings
138eadff302SIvan T. Ivanov  * @base: Address base in SPMI device.
139eadff302SIvan T. Ivanov  * @irq: IRQ number which this GPIO generate.
140eadff302SIvan T. Ivanov  * @is_enabled: Set to false when GPIO should be put in high Z state.
141eadff302SIvan T. Ivanov  * @out_value: Cached pin output value
142eadff302SIvan T. Ivanov  * @have_buffer: Set to true if GPIO output could be configured in push-pull,
143eadff302SIvan T. Ivanov  *	open-drain or open-source mode.
144eadff302SIvan T. Ivanov  * @output_enabled: Set to true if GPIO output logic is enabled.
145eadff302SIvan T. Ivanov  * @input_enabled: Set to true if GPIO input buffer logic is enabled.
146d7b5f5ccSFenglin Wu  * @analog_pass: Set to true if GPIO is in analog-pass-through mode.
147d7b5f5ccSFenglin Wu  * @lv_mv_type: Set to true if GPIO subtype is GPIO_LV(0x10) or GPIO_MV(0x11).
148eadff302SIvan T. Ivanov  * @num_sources: Number of power-sources supported by this GPIO.
149eadff302SIvan T. Ivanov  * @power_source: Current power-source used.
150eadff302SIvan T. Ivanov  * @buffer_type: Push-pull, open-drain or open-source.
151eadff302SIvan T. Ivanov  * @pullup: Constant current which flow trough GPIO output buffer.
152eadff302SIvan T. Ivanov  * @strength: No, Low, Medium, High
153eadff302SIvan T. Ivanov  * @function: See pmic_gpio_functions[]
154d7b5f5ccSFenglin Wu  * @atest: the ATEST selection for GPIO analog-pass-through mode
155223463fcSFenglin Wu  * @dtest_buffer: the DTEST buffer selection for digital input mode.
156eadff302SIvan T. Ivanov  */
157eadff302SIvan T. Ivanov struct pmic_gpio_pad {
158eadff302SIvan T. Ivanov 	u16		base;
159eadff302SIvan T. Ivanov 	int		irq;
160eadff302SIvan T. Ivanov 	bool		is_enabled;
161eadff302SIvan T. Ivanov 	bool		out_value;
162eadff302SIvan T. Ivanov 	bool		have_buffer;
163eadff302SIvan T. Ivanov 	bool		output_enabled;
164eadff302SIvan T. Ivanov 	bool		input_enabled;
165d7b5f5ccSFenglin Wu 	bool		analog_pass;
166d7b5f5ccSFenglin Wu 	bool		lv_mv_type;
167eadff302SIvan T. Ivanov 	unsigned int	num_sources;
168eadff302SIvan T. Ivanov 	unsigned int	power_source;
169eadff302SIvan T. Ivanov 	unsigned int	buffer_type;
170eadff302SIvan T. Ivanov 	unsigned int	pullup;
171eadff302SIvan T. Ivanov 	unsigned int	strength;
172eadff302SIvan T. Ivanov 	unsigned int	function;
173d7b5f5ccSFenglin Wu 	unsigned int	atest;
174223463fcSFenglin Wu 	unsigned int	dtest_buffer;
175eadff302SIvan T. Ivanov };
176eadff302SIvan T. Ivanov 
177eadff302SIvan T. Ivanov struct pmic_gpio_state {
178eadff302SIvan T. Ivanov 	struct device	*dev;
179eadff302SIvan T. Ivanov 	struct regmap	*map;
180eadff302SIvan T. Ivanov 	struct pinctrl_dev *ctrl;
181eadff302SIvan T. Ivanov 	struct gpio_chip chip;
182eadff302SIvan T. Ivanov };
183eadff302SIvan T. Ivanov 
184f684e4acSLinus Walleij static const struct pinconf_generic_params pmic_gpio_bindings[] = {
1857382b623SSoren Brinkmann 	{"qcom,pull-up-strength",	PMIC_GPIO_CONF_PULL_UP,		0},
1867382b623SSoren Brinkmann 	{"qcom,drive-strength",		PMIC_GPIO_CONF_STRENGTH,	0},
187d7b5f5ccSFenglin Wu 	{"qcom,atest",			PMIC_GPIO_CONF_ATEST,		0},
188d7b5f5ccSFenglin Wu 	{"qcom,analog-pass",		PMIC_GPIO_CONF_ANALOG_PASS,	0},
189223463fcSFenglin Wu 	{"qcom,dtest-buffer",           PMIC_GPIO_CONF_DTEST_BUFFER,    0},
190eadff302SIvan T. Ivanov };
191eadff302SIvan T. Ivanov 
1924f06266aSArnd Bergmann #ifdef CONFIG_DEBUG_FS
1937382b623SSoren Brinkmann static const struct pin_config_item pmic_conf_items[ARRAY_SIZE(pmic_gpio_bindings)] = {
1947382b623SSoren Brinkmann 	PCONFDUMP(PMIC_GPIO_CONF_PULL_UP,  "pull up strength", NULL, true),
1957382b623SSoren Brinkmann 	PCONFDUMP(PMIC_GPIO_CONF_STRENGTH, "drive-strength", NULL, true),
196d7b5f5ccSFenglin Wu 	PCONFDUMP(PMIC_GPIO_CONF_ATEST, "atest", NULL, true),
197d7b5f5ccSFenglin Wu 	PCONFDUMP(PMIC_GPIO_CONF_ANALOG_PASS, "analog-pass", NULL, true),
198223463fcSFenglin Wu 	PCONFDUMP(PMIC_GPIO_CONF_DTEST_BUFFER, "dtest-buffer", NULL, true),
199eadff302SIvan T. Ivanov };
2004f06266aSArnd Bergmann #endif
201eadff302SIvan T. Ivanov 
202eadff302SIvan T. Ivanov static const char *const pmic_gpio_groups[] = {
203eadff302SIvan T. Ivanov 	"gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", "gpio8",
204eadff302SIvan T. Ivanov 	"gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", "gpio15",
205eadff302SIvan T. Ivanov 	"gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", "gpio22",
206eadff302SIvan T. Ivanov 	"gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29",
207eadff302SIvan T. Ivanov 	"gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36",
208eadff302SIvan T. Ivanov };
209eadff302SIvan T. Ivanov 
210eadff302SIvan T. Ivanov static const char *const pmic_gpio_functions[] = {
211d7b5f5ccSFenglin Wu 	[PMIC_GPIO_FUNC_INDEX_NORMAL]	= PMIC_GPIO_FUNC_NORMAL,
212d7b5f5ccSFenglin Wu 	[PMIC_GPIO_FUNC_INDEX_PAIRED]	= PMIC_GPIO_FUNC_PAIRED,
213d7b5f5ccSFenglin Wu 	[PMIC_GPIO_FUNC_INDEX_FUNC1]	= PMIC_GPIO_FUNC_FUNC1,
214d7b5f5ccSFenglin Wu 	[PMIC_GPIO_FUNC_INDEX_FUNC2]	= PMIC_GPIO_FUNC_FUNC2,
215d7b5f5ccSFenglin Wu 	[PMIC_GPIO_FUNC_INDEX_FUNC3]	= PMIC_GPIO_FUNC_FUNC3,
216d7b5f5ccSFenglin Wu 	[PMIC_GPIO_FUNC_INDEX_FUNC4]	= PMIC_GPIO_FUNC_FUNC4,
217d7b5f5ccSFenglin Wu 	[PMIC_GPIO_FUNC_INDEX_DTEST1]	= PMIC_GPIO_FUNC_DTEST1,
218d7b5f5ccSFenglin Wu 	[PMIC_GPIO_FUNC_INDEX_DTEST2]	= PMIC_GPIO_FUNC_DTEST2,
219d7b5f5ccSFenglin Wu 	[PMIC_GPIO_FUNC_INDEX_DTEST3]	= PMIC_GPIO_FUNC_DTEST3,
220d7b5f5ccSFenglin Wu 	[PMIC_GPIO_FUNC_INDEX_DTEST4]	= PMIC_GPIO_FUNC_DTEST4,
221eadff302SIvan T. Ivanov };
222eadff302SIvan T. Ivanov 
223eadff302SIvan T. Ivanov static int pmic_gpio_read(struct pmic_gpio_state *state,
224eadff302SIvan T. Ivanov 			  struct pmic_gpio_pad *pad, unsigned int addr)
225eadff302SIvan T. Ivanov {
226eadff302SIvan T. Ivanov 	unsigned int val;
227eadff302SIvan T. Ivanov 	int ret;
228eadff302SIvan T. Ivanov 
229eadff302SIvan T. Ivanov 	ret = regmap_read(state->map, pad->base + addr, &val);
230eadff302SIvan T. Ivanov 	if (ret < 0)
231eadff302SIvan T. Ivanov 		dev_err(state->dev, "read 0x%x failed\n", addr);
232eadff302SIvan T. Ivanov 	else
233eadff302SIvan T. Ivanov 		ret = val;
234eadff302SIvan T. Ivanov 
235eadff302SIvan T. Ivanov 	return ret;
236eadff302SIvan T. Ivanov }
237eadff302SIvan T. Ivanov 
238eadff302SIvan T. Ivanov static int pmic_gpio_write(struct pmic_gpio_state *state,
239eadff302SIvan T. Ivanov 			   struct pmic_gpio_pad *pad, unsigned int addr,
240eadff302SIvan T. Ivanov 			   unsigned int val)
241eadff302SIvan T. Ivanov {
242eadff302SIvan T. Ivanov 	int ret;
243eadff302SIvan T. Ivanov 
244eadff302SIvan T. Ivanov 	ret = regmap_write(state->map, pad->base + addr, val);
245eadff302SIvan T. Ivanov 	if (ret < 0)
246eadff302SIvan T. Ivanov 		dev_err(state->dev, "write 0x%x failed\n", addr);
247eadff302SIvan T. Ivanov 
248eadff302SIvan T. Ivanov 	return ret;
249eadff302SIvan T. Ivanov }
250eadff302SIvan T. Ivanov 
251eadff302SIvan T. Ivanov static int pmic_gpio_get_groups_count(struct pinctrl_dev *pctldev)
252eadff302SIvan T. Ivanov {
253eadff302SIvan T. Ivanov 	/* Every PIN is a group */
254eadff302SIvan T. Ivanov 	return pctldev->desc->npins;
255eadff302SIvan T. Ivanov }
256eadff302SIvan T. Ivanov 
257eadff302SIvan T. Ivanov static const char *pmic_gpio_get_group_name(struct pinctrl_dev *pctldev,
258eadff302SIvan T. Ivanov 					    unsigned pin)
259eadff302SIvan T. Ivanov {
260eadff302SIvan T. Ivanov 	return pctldev->desc->pins[pin].name;
261eadff302SIvan T. Ivanov }
262eadff302SIvan T. Ivanov 
263eadff302SIvan T. Ivanov static int pmic_gpio_get_group_pins(struct pinctrl_dev *pctldev, unsigned pin,
264eadff302SIvan T. Ivanov 				    const unsigned **pins, unsigned *num_pins)
265eadff302SIvan T. Ivanov {
266eadff302SIvan T. Ivanov 	*pins = &pctldev->desc->pins[pin].number;
267eadff302SIvan T. Ivanov 	*num_pins = 1;
268eadff302SIvan T. Ivanov 	return 0;
269eadff302SIvan T. Ivanov }
270eadff302SIvan T. Ivanov 
271eadff302SIvan T. Ivanov static const struct pinctrl_ops pmic_gpio_pinctrl_ops = {
272eadff302SIvan T. Ivanov 	.get_groups_count	= pmic_gpio_get_groups_count,
273eadff302SIvan T. Ivanov 	.get_group_name		= pmic_gpio_get_group_name,
274eadff302SIvan T. Ivanov 	.get_group_pins		= pmic_gpio_get_group_pins,
2757382b623SSoren Brinkmann 	.dt_node_to_map		= pinconf_generic_dt_node_to_map_group,
276d32f7fd3SIrina Tirdea 	.dt_free_map		= pinctrl_utils_free_map,
277eadff302SIvan T. Ivanov };
278eadff302SIvan T. Ivanov 
279eadff302SIvan T. Ivanov static int pmic_gpio_get_functions_count(struct pinctrl_dev *pctldev)
280eadff302SIvan T. Ivanov {
281eadff302SIvan T. Ivanov 	return ARRAY_SIZE(pmic_gpio_functions);
282eadff302SIvan T. Ivanov }
283eadff302SIvan T. Ivanov 
284eadff302SIvan T. Ivanov static const char *pmic_gpio_get_function_name(struct pinctrl_dev *pctldev,
285eadff302SIvan T. Ivanov 					       unsigned function)
286eadff302SIvan T. Ivanov {
287eadff302SIvan T. Ivanov 	return pmic_gpio_functions[function];
288eadff302SIvan T. Ivanov }
289eadff302SIvan T. Ivanov 
290eadff302SIvan T. Ivanov static int pmic_gpio_get_function_groups(struct pinctrl_dev *pctldev,
291eadff302SIvan T. Ivanov 					 unsigned function,
292eadff302SIvan T. Ivanov 					 const char *const **groups,
293eadff302SIvan T. Ivanov 					 unsigned *const num_qgroups)
294eadff302SIvan T. Ivanov {
295eadff302SIvan T. Ivanov 	*groups = pmic_gpio_groups;
296eadff302SIvan T. Ivanov 	*num_qgroups = pctldev->desc->npins;
297eadff302SIvan T. Ivanov 	return 0;
298eadff302SIvan T. Ivanov }
299eadff302SIvan T. Ivanov 
300eadff302SIvan T. Ivanov static int pmic_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned function,
301eadff302SIvan T. Ivanov 				unsigned pin)
302eadff302SIvan T. Ivanov {
303eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev);
304eadff302SIvan T. Ivanov 	struct pmic_gpio_pad *pad;
305eadff302SIvan T. Ivanov 	unsigned int val;
306eadff302SIvan T. Ivanov 	int ret;
307eadff302SIvan T. Ivanov 
308d7b5f5ccSFenglin Wu 	if (function > PMIC_GPIO_FUNC_INDEX_DTEST4) {
309d7b5f5ccSFenglin Wu 		pr_err("function: %d is not defined\n", function);
310d7b5f5ccSFenglin Wu 		return -EINVAL;
311d7b5f5ccSFenglin Wu 	}
312d7b5f5ccSFenglin Wu 
313eadff302SIvan T. Ivanov 	pad = pctldev->desc->pins[pin].drv_data;
314d7b5f5ccSFenglin Wu 	/*
315d7b5f5ccSFenglin Wu 	 * Non-LV/MV subtypes only support 2 special functions,
316d7b5f5ccSFenglin Wu 	 * offsetting the dtestx function values by 2
317d7b5f5ccSFenglin Wu 	 */
318d7b5f5ccSFenglin Wu 	if (!pad->lv_mv_type) {
319d7b5f5ccSFenglin Wu 		if (function == PMIC_GPIO_FUNC_INDEX_FUNC3 ||
320d7b5f5ccSFenglin Wu 				function == PMIC_GPIO_FUNC_INDEX_FUNC4) {
321d7b5f5ccSFenglin Wu 			pr_err("LV/MV subtype doesn't have func3/func4\n");
322d7b5f5ccSFenglin Wu 			return -EINVAL;
323d7b5f5ccSFenglin Wu 		}
324d7b5f5ccSFenglin Wu 		if (function >= PMIC_GPIO_FUNC_INDEX_DTEST1)
325d7b5f5ccSFenglin Wu 			function -= (PMIC_GPIO_FUNC_INDEX_DTEST1 -
326d7b5f5ccSFenglin Wu 					PMIC_GPIO_FUNC_INDEX_FUNC3);
327d7b5f5ccSFenglin Wu 	}
328eadff302SIvan T. Ivanov 
329eadff302SIvan T. Ivanov 	pad->function = function;
330eadff302SIvan T. Ivanov 
331d7b5f5ccSFenglin Wu 	if (pad->analog_pass)
332d7b5f5ccSFenglin Wu 		val = PMIC_GPIO_MODE_ANALOG_PASS_THRU;
333d7b5f5ccSFenglin Wu 	else if (pad->output_enabled && pad->input_enabled)
334d7b5f5ccSFenglin Wu 		val = PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT;
335d7b5f5ccSFenglin Wu 	else if (pad->output_enabled)
336d7b5f5ccSFenglin Wu 		val = PMIC_GPIO_MODE_DIGITAL_OUTPUT;
337eadff302SIvan T. Ivanov 	else
338d7b5f5ccSFenglin Wu 		val = PMIC_GPIO_MODE_DIGITAL_INPUT;
339eadff302SIvan T. Ivanov 
340d7b5f5ccSFenglin Wu 	if (pad->lv_mv_type) {
341d7b5f5ccSFenglin Wu 		ret = pmic_gpio_write(state, pad,
342d7b5f5ccSFenglin Wu 				PMIC_GPIO_REG_MODE_CTL, val);
343d7b5f5ccSFenglin Wu 		if (ret < 0)
344d7b5f5ccSFenglin Wu 			return ret;
345d7b5f5ccSFenglin Wu 
346d7b5f5ccSFenglin Wu 		val = pad->atest - 1;
347d7b5f5ccSFenglin Wu 		ret = pmic_gpio_write(state, pad,
348d7b5f5ccSFenglin Wu 				PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL, val);
349d7b5f5ccSFenglin Wu 		if (ret < 0)
350d7b5f5ccSFenglin Wu 			return ret;
351d7b5f5ccSFenglin Wu 
352d7b5f5ccSFenglin Wu 		val = pad->out_value
353d7b5f5ccSFenglin Wu 			<< PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT;
354d7b5f5ccSFenglin Wu 		val |= pad->function
355d7b5f5ccSFenglin Wu 			& PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK;
356d7b5f5ccSFenglin Wu 		ret = pmic_gpio_write(state, pad,
357d7b5f5ccSFenglin Wu 			PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL, val);
358d7b5f5ccSFenglin Wu 		if (ret < 0)
359d7b5f5ccSFenglin Wu 			return ret;
360d7b5f5ccSFenglin Wu 	} else {
361dc391502SIvan T. Ivanov 		val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT;
362eadff302SIvan T. Ivanov 		val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT;
363eadff302SIvan T. Ivanov 		val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT;
364eadff302SIvan T. Ivanov 
365eadff302SIvan T. Ivanov 		ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val);
366eadff302SIvan T. Ivanov 		if (ret < 0)
367eadff302SIvan T. Ivanov 			return ret;
368d7b5f5ccSFenglin Wu 	}
369eadff302SIvan T. Ivanov 
370eadff302SIvan T. Ivanov 	val = pad->is_enabled << PMIC_GPIO_REG_MASTER_EN_SHIFT;
371eadff302SIvan T. Ivanov 
372eadff302SIvan T. Ivanov 	return pmic_gpio_write(state, pad, PMIC_GPIO_REG_EN_CTL, val);
373eadff302SIvan T. Ivanov }
374eadff302SIvan T. Ivanov 
375eadff302SIvan T. Ivanov static const struct pinmux_ops pmic_gpio_pinmux_ops = {
376eadff302SIvan T. Ivanov 	.get_functions_count	= pmic_gpio_get_functions_count,
377eadff302SIvan T. Ivanov 	.get_function_name	= pmic_gpio_get_function_name,
378eadff302SIvan T. Ivanov 	.get_function_groups	= pmic_gpio_get_function_groups,
379eadff302SIvan T. Ivanov 	.set_mux		= pmic_gpio_set_mux,
380eadff302SIvan T. Ivanov };
381eadff302SIvan T. Ivanov 
382eadff302SIvan T. Ivanov static int pmic_gpio_config_get(struct pinctrl_dev *pctldev,
383eadff302SIvan T. Ivanov 				unsigned int pin, unsigned long *config)
384eadff302SIvan T. Ivanov {
385eadff302SIvan T. Ivanov 	unsigned param = pinconf_to_config_param(*config);
386eadff302SIvan T. Ivanov 	struct pmic_gpio_pad *pad;
387eadff302SIvan T. Ivanov 	unsigned arg;
388eadff302SIvan T. Ivanov 
389eadff302SIvan T. Ivanov 	pad = pctldev->desc->pins[pin].drv_data;
390eadff302SIvan T. Ivanov 
391eadff302SIvan T. Ivanov 	switch (param) {
392eadff302SIvan T. Ivanov 	case PIN_CONFIG_DRIVE_PUSH_PULL:
3931cf86bc2SDouglas Anderson 		if (pad->buffer_type != PMIC_GPIO_OUT_BUF_CMOS)
3941cf86bc2SDouglas Anderson 			return -EINVAL;
3951cf86bc2SDouglas Anderson 		arg = 1;
396eadff302SIvan T. Ivanov 		break;
397eadff302SIvan T. Ivanov 	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
3981cf86bc2SDouglas Anderson 		if (pad->buffer_type != PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS)
3991cf86bc2SDouglas Anderson 			return -EINVAL;
4001cf86bc2SDouglas Anderson 		arg = 1;
401eadff302SIvan T. Ivanov 		break;
402eadff302SIvan T. Ivanov 	case PIN_CONFIG_DRIVE_OPEN_SOURCE:
4031cf86bc2SDouglas Anderson 		if (pad->buffer_type != PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS)
4041cf86bc2SDouglas Anderson 			return -EINVAL;
4051cf86bc2SDouglas Anderson 		arg = 1;
406eadff302SIvan T. Ivanov 		break;
407eadff302SIvan T. Ivanov 	case PIN_CONFIG_BIAS_PULL_DOWN:
4081cf86bc2SDouglas Anderson 		if (pad->pullup != PMIC_GPIO_PULL_DOWN)
4091cf86bc2SDouglas Anderson 			return -EINVAL;
4101cf86bc2SDouglas Anderson 		arg = 1;
411eadff302SIvan T. Ivanov 		break;
412eadff302SIvan T. Ivanov 	case PIN_CONFIG_BIAS_DISABLE:
4131cf86bc2SDouglas Anderson 		if (pad->pullup != PMIC_GPIO_PULL_DISABLE)
4141cf86bc2SDouglas Anderson 			return -EINVAL;
4151cf86bc2SDouglas Anderson 		arg = 1;
416eadff302SIvan T. Ivanov 		break;
417eadff302SIvan T. Ivanov 	case PIN_CONFIG_BIAS_PULL_UP:
4181cf86bc2SDouglas Anderson 		if (pad->pullup != PMIC_GPIO_PULL_UP_30)
4191cf86bc2SDouglas Anderson 			return -EINVAL;
4201cf86bc2SDouglas Anderson 		arg = 1;
421eadff302SIvan T. Ivanov 		break;
422eadff302SIvan T. Ivanov 	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
4231cf86bc2SDouglas Anderson 		if (pad->is_enabled)
4241cf86bc2SDouglas Anderson 			return -EINVAL;
4251cf86bc2SDouglas Anderson 		arg = 1;
426eadff302SIvan T. Ivanov 		break;
427eadff302SIvan T. Ivanov 	case PIN_CONFIG_POWER_SOURCE:
428eadff302SIvan T. Ivanov 		arg = pad->power_source;
429eadff302SIvan T. Ivanov 		break;
430eadff302SIvan T. Ivanov 	case PIN_CONFIG_INPUT_ENABLE:
4311cf86bc2SDouglas Anderson 		if (!pad->input_enabled)
4321cf86bc2SDouglas Anderson 			return -EINVAL;
4331cf86bc2SDouglas Anderson 		arg = 1;
434eadff302SIvan T. Ivanov 		break;
435eadff302SIvan T. Ivanov 	case PIN_CONFIG_OUTPUT:
436eadff302SIvan T. Ivanov 		arg = pad->out_value;
437eadff302SIvan T. Ivanov 		break;
438eadff302SIvan T. Ivanov 	case PMIC_GPIO_CONF_PULL_UP:
439eadff302SIvan T. Ivanov 		arg = pad->pullup;
440eadff302SIvan T. Ivanov 		break;
441eadff302SIvan T. Ivanov 	case PMIC_GPIO_CONF_STRENGTH:
442eadff302SIvan T. Ivanov 		arg = pad->strength;
443eadff302SIvan T. Ivanov 		break;
444d7b5f5ccSFenglin Wu 	case PMIC_GPIO_CONF_ATEST:
445d7b5f5ccSFenglin Wu 		arg = pad->atest;
446d7b5f5ccSFenglin Wu 		break;
447d7b5f5ccSFenglin Wu 	case PMIC_GPIO_CONF_ANALOG_PASS:
448d7b5f5ccSFenglin Wu 		arg = pad->analog_pass;
449d7b5f5ccSFenglin Wu 		break;
450223463fcSFenglin Wu 	case PMIC_GPIO_CONF_DTEST_BUFFER:
451223463fcSFenglin Wu 		arg = pad->dtest_buffer;
452223463fcSFenglin Wu 		break;
453eadff302SIvan T. Ivanov 	default:
454eadff302SIvan T. Ivanov 		return -EINVAL;
455eadff302SIvan T. Ivanov 	}
456eadff302SIvan T. Ivanov 
457eadff302SIvan T. Ivanov 	*config = pinconf_to_config_packed(param, arg);
458eadff302SIvan T. Ivanov 	return 0;
459eadff302SIvan T. Ivanov }
460eadff302SIvan T. Ivanov 
461eadff302SIvan T. Ivanov static int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
462eadff302SIvan T. Ivanov 				unsigned long *configs, unsigned nconfs)
463eadff302SIvan T. Ivanov {
464eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev);
465eadff302SIvan T. Ivanov 	struct pmic_gpio_pad *pad;
466eadff302SIvan T. Ivanov 	unsigned param, arg;
467eadff302SIvan T. Ivanov 	unsigned int val;
468eadff302SIvan T. Ivanov 	int i, ret;
469eadff302SIvan T. Ivanov 
470eadff302SIvan T. Ivanov 	pad = pctldev->desc->pins[pin].drv_data;
471eadff302SIvan T. Ivanov 
4726cb74f44SFenglin Wu 	pad->is_enabled = true;
473eadff302SIvan T. Ivanov 	for (i = 0; i < nconfs; i++) {
474eadff302SIvan T. Ivanov 		param = pinconf_to_config_param(configs[i]);
475eadff302SIvan T. Ivanov 		arg = pinconf_to_config_argument(configs[i]);
476eadff302SIvan T. Ivanov 
477eadff302SIvan T. Ivanov 		switch (param) {
478eadff302SIvan T. Ivanov 		case PIN_CONFIG_DRIVE_PUSH_PULL:
479eadff302SIvan T. Ivanov 			pad->buffer_type = PMIC_GPIO_OUT_BUF_CMOS;
480eadff302SIvan T. Ivanov 			break;
481eadff302SIvan T. Ivanov 		case PIN_CONFIG_DRIVE_OPEN_DRAIN:
482eadff302SIvan T. Ivanov 			if (!pad->have_buffer)
483eadff302SIvan T. Ivanov 				return -EINVAL;
484eadff302SIvan T. Ivanov 			pad->buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS;
485eadff302SIvan T. Ivanov 			break;
486eadff302SIvan T. Ivanov 		case PIN_CONFIG_DRIVE_OPEN_SOURCE:
487eadff302SIvan T. Ivanov 			if (!pad->have_buffer)
488eadff302SIvan T. Ivanov 				return -EINVAL;
489eadff302SIvan T. Ivanov 			pad->buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS;
490eadff302SIvan T. Ivanov 			break;
491eadff302SIvan T. Ivanov 		case PIN_CONFIG_BIAS_DISABLE:
492eadff302SIvan T. Ivanov 			pad->pullup = PMIC_GPIO_PULL_DISABLE;
493eadff302SIvan T. Ivanov 			break;
494eadff302SIvan T. Ivanov 		case PIN_CONFIG_BIAS_PULL_UP:
495eadff302SIvan T. Ivanov 			pad->pullup = PMIC_GPIO_PULL_UP_30;
496eadff302SIvan T. Ivanov 			break;
497eadff302SIvan T. Ivanov 		case PIN_CONFIG_BIAS_PULL_DOWN:
498eadff302SIvan T. Ivanov 			if (arg)
499eadff302SIvan T. Ivanov 				pad->pullup = PMIC_GPIO_PULL_DOWN;
500eadff302SIvan T. Ivanov 			else
501eadff302SIvan T. Ivanov 				pad->pullup = PMIC_GPIO_PULL_DISABLE;
502eadff302SIvan T. Ivanov 			break;
503eadff302SIvan T. Ivanov 		case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
504eadff302SIvan T. Ivanov 			pad->is_enabled = false;
505eadff302SIvan T. Ivanov 			break;
506eadff302SIvan T. Ivanov 		case PIN_CONFIG_POWER_SOURCE:
5074e83ac4cSFenglin Wu 			if (arg >= pad->num_sources)
508eadff302SIvan T. Ivanov 				return -EINVAL;
509eadff302SIvan T. Ivanov 			pad->power_source = arg;
510eadff302SIvan T. Ivanov 			break;
511eadff302SIvan T. Ivanov 		case PIN_CONFIG_INPUT_ENABLE:
512eadff302SIvan T. Ivanov 			pad->input_enabled = arg ? true : false;
513eadff302SIvan T. Ivanov 			break;
514eadff302SIvan T. Ivanov 		case PIN_CONFIG_OUTPUT:
515eadff302SIvan T. Ivanov 			pad->output_enabled = true;
516eadff302SIvan T. Ivanov 			pad->out_value = arg;
517eadff302SIvan T. Ivanov 			break;
518eadff302SIvan T. Ivanov 		case PMIC_GPIO_CONF_PULL_UP:
519eadff302SIvan T. Ivanov 			if (arg > PMIC_GPIO_PULL_UP_1P5_30)
520eadff302SIvan T. Ivanov 				return -EINVAL;
521eadff302SIvan T. Ivanov 			pad->pullup = arg;
522eadff302SIvan T. Ivanov 			break;
523eadff302SIvan T. Ivanov 		case PMIC_GPIO_CONF_STRENGTH:
524eadff302SIvan T. Ivanov 			if (arg > PMIC_GPIO_STRENGTH_LOW)
525eadff302SIvan T. Ivanov 				return -EINVAL;
526eadff302SIvan T. Ivanov 			pad->strength = arg;
527eadff302SIvan T. Ivanov 			break;
528d7b5f5ccSFenglin Wu 		case PMIC_GPIO_CONF_ATEST:
529d7b5f5ccSFenglin Wu 			if (!pad->lv_mv_type || arg > 4)
530d7b5f5ccSFenglin Wu 				return -EINVAL;
531d7b5f5ccSFenglin Wu 			pad->atest = arg;
532d7b5f5ccSFenglin Wu 			break;
533d7b5f5ccSFenglin Wu 		case PMIC_GPIO_CONF_ANALOG_PASS:
534d7b5f5ccSFenglin Wu 			if (!pad->lv_mv_type)
535d7b5f5ccSFenglin Wu 				return -EINVAL;
536d7b5f5ccSFenglin Wu 			pad->analog_pass = true;
537d7b5f5ccSFenglin Wu 			break;
538223463fcSFenglin Wu 		case PMIC_GPIO_CONF_DTEST_BUFFER:
539223463fcSFenglin Wu 			if (arg > 4)
540223463fcSFenglin Wu 				return -EINVAL;
541223463fcSFenglin Wu 			pad->dtest_buffer = arg;
542223463fcSFenglin Wu 			break;
543eadff302SIvan T. Ivanov 		default:
544eadff302SIvan T. Ivanov 			return -EINVAL;
545eadff302SIvan T. Ivanov 		}
546eadff302SIvan T. Ivanov 	}
547eadff302SIvan T. Ivanov 
548eadff302SIvan T. Ivanov 	val = pad->power_source << PMIC_GPIO_REG_VIN_SHIFT;
549eadff302SIvan T. Ivanov 
550eadff302SIvan T. Ivanov 	ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL, val);
551eadff302SIvan T. Ivanov 	if (ret < 0)
552eadff302SIvan T. Ivanov 		return ret;
553eadff302SIvan T. Ivanov 
554eadff302SIvan T. Ivanov 	val = pad->pullup << PMIC_GPIO_REG_PULL_SHIFT;
555eadff302SIvan T. Ivanov 
556eadff302SIvan T. Ivanov 	ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_PULL_CTL, val);
557eadff302SIvan T. Ivanov 	if (ret < 0)
558eadff302SIvan T. Ivanov 		return ret;
559eadff302SIvan T. Ivanov 
560eadff302SIvan T. Ivanov 	val = pad->buffer_type << PMIC_GPIO_REG_OUT_TYPE_SHIFT;
561982df6aeSIvan T. Ivanov 	val |= pad->strength << PMIC_GPIO_REG_OUT_STRENGTH_SHIFT;
562eadff302SIvan T. Ivanov 
563eadff302SIvan T. Ivanov 	ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL, val);
564eadff302SIvan T. Ivanov 	if (ret < 0)
565eadff302SIvan T. Ivanov 		return ret;
566eadff302SIvan T. Ivanov 
567223463fcSFenglin Wu 	if (pad->dtest_buffer == 0) {
568223463fcSFenglin Wu 		val = 0;
569223463fcSFenglin Wu 	} else {
570223463fcSFenglin Wu 		if (pad->lv_mv_type) {
571223463fcSFenglin Wu 			val = pad->dtest_buffer - 1;
572223463fcSFenglin Wu 			val |= PMIC_GPIO_LV_MV_DIG_IN_DTEST_EN;
573223463fcSFenglin Wu 		} else {
574223463fcSFenglin Wu 			val = BIT(pad->dtest_buffer - 1);
575223463fcSFenglin Wu 		}
576223463fcSFenglin Wu 	}
577223463fcSFenglin Wu 	ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_IN_CTL, val);
578223463fcSFenglin Wu 	if (ret < 0)
579223463fcSFenglin Wu 		return ret;
580223463fcSFenglin Wu 
581d7b5f5ccSFenglin Wu 	if (pad->analog_pass)
582d7b5f5ccSFenglin Wu 		val = PMIC_GPIO_MODE_ANALOG_PASS_THRU;
583d7b5f5ccSFenglin Wu 	else if (pad->output_enabled && pad->input_enabled)
584d7b5f5ccSFenglin Wu 		val = PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT;
585d7b5f5ccSFenglin Wu 	else if (pad->output_enabled)
586d7b5f5ccSFenglin Wu 		val = PMIC_GPIO_MODE_DIGITAL_OUTPUT;
587eadff302SIvan T. Ivanov 	else
588d7b5f5ccSFenglin Wu 		val = PMIC_GPIO_MODE_DIGITAL_INPUT;
589eadff302SIvan T. Ivanov 
590d7b5f5ccSFenglin Wu 	if (pad->lv_mv_type) {
591d7b5f5ccSFenglin Wu 		ret = pmic_gpio_write(state, pad,
592d7b5f5ccSFenglin Wu 				PMIC_GPIO_REG_MODE_CTL, val);
593d7b5f5ccSFenglin Wu 		if (ret < 0)
594d7b5f5ccSFenglin Wu 			return ret;
595d7b5f5ccSFenglin Wu 
596d7b5f5ccSFenglin Wu 		val = pad->atest - 1;
597d7b5f5ccSFenglin Wu 		ret = pmic_gpio_write(state, pad,
598d7b5f5ccSFenglin Wu 				PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL, val);
599d7b5f5ccSFenglin Wu 		if (ret < 0)
600d7b5f5ccSFenglin Wu 			return ret;
601d7b5f5ccSFenglin Wu 
602d7b5f5ccSFenglin Wu 		val = pad->out_value
603d7b5f5ccSFenglin Wu 			<< PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT;
604d7b5f5ccSFenglin Wu 		val |= pad->function
605d7b5f5ccSFenglin Wu 			& PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK;
606d7b5f5ccSFenglin Wu 		ret = pmic_gpio_write(state, pad,
607d7b5f5ccSFenglin Wu 			PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL, val);
608d7b5f5ccSFenglin Wu 		if (ret < 0)
609d7b5f5ccSFenglin Wu 			return ret;
610d7b5f5ccSFenglin Wu 	} else {
611eadff302SIvan T. Ivanov 		val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT;
612eadff302SIvan T. Ivanov 		val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT;
613eadff302SIvan T. Ivanov 		val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT;
614eadff302SIvan T. Ivanov 
615d7b5f5ccSFenglin Wu 		ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val);
616d7b5f5ccSFenglin Wu 		if (ret < 0)
617d7b5f5ccSFenglin Wu 			return ret;
618d7b5f5ccSFenglin Wu 	}
619d7b5f5ccSFenglin Wu 
6206cb74f44SFenglin Wu 	val = pad->is_enabled << PMIC_GPIO_REG_MASTER_EN_SHIFT;
6216cb74f44SFenglin Wu 
6226cb74f44SFenglin Wu 	ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_EN_CTL, val);
6236cb74f44SFenglin Wu 
624d7b5f5ccSFenglin Wu 	return ret;
625eadff302SIvan T. Ivanov }
626eadff302SIvan T. Ivanov 
627eadff302SIvan T. Ivanov static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev,
628eadff302SIvan T. Ivanov 				      struct seq_file *s, unsigned pin)
629eadff302SIvan T. Ivanov {
630eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev);
631eadff302SIvan T. Ivanov 	struct pmic_gpio_pad *pad;
632d7b5f5ccSFenglin Wu 	int ret, val, function;
633eadff302SIvan T. Ivanov 
634eadff302SIvan T. Ivanov 	static const char *const biases[] = {
635eadff302SIvan T. Ivanov 		"pull-up 30uA", "pull-up 1.5uA", "pull-up 31.5uA",
636eadff302SIvan T. Ivanov 		"pull-up 1.5uA + 30uA boost", "pull-down 10uA", "no pull"
637eadff302SIvan T. Ivanov 	};
638eadff302SIvan T. Ivanov 	static const char *const buffer_types[] = {
639eadff302SIvan T. Ivanov 		"push-pull", "open-drain", "open-source"
640eadff302SIvan T. Ivanov 	};
641eadff302SIvan T. Ivanov 	static const char *const strengths[] = {
642eadff302SIvan T. Ivanov 		"no", "high", "medium", "low"
643eadff302SIvan T. Ivanov 	};
644eadff302SIvan T. Ivanov 
645eadff302SIvan T. Ivanov 	pad = pctldev->desc->pins[pin].drv_data;
646eadff302SIvan T. Ivanov 
647eadff302SIvan T. Ivanov 	seq_printf(s, " gpio%-2d:", pin + PMIC_GPIO_PHYSICAL_OFFSET);
648eadff302SIvan T. Ivanov 
649eadff302SIvan T. Ivanov 	val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_EN_CTL);
650eadff302SIvan T. Ivanov 
651eadff302SIvan T. Ivanov 	if (val < 0 || !(val >> PMIC_GPIO_REG_MASTER_EN_SHIFT)) {
652eadff302SIvan T. Ivanov 		seq_puts(s, " ---");
653eadff302SIvan T. Ivanov 	} else {
65424a66618SIvan T. Ivanov 		if (pad->input_enabled) {
655eadff302SIvan T. Ivanov 			ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS);
65624a66618SIvan T. Ivanov 			if (ret < 0)
65724a66618SIvan T. Ivanov 				return;
65824a66618SIvan T. Ivanov 
659eadff302SIvan T. Ivanov 			ret &= PMIC_MPP_REG_RT_STS_VAL_MASK;
660eadff302SIvan T. Ivanov 			pad->out_value = ret;
661eadff302SIvan T. Ivanov 		}
662d7b5f5ccSFenglin Wu 		/*
663d7b5f5ccSFenglin Wu 		 * For the non-LV/MV subtypes only 2 special functions are
664d7b5f5ccSFenglin Wu 		 * available, offsetting the dtest function values by 2.
665d7b5f5ccSFenglin Wu 		 */
666d7b5f5ccSFenglin Wu 		function = pad->function;
667d7b5f5ccSFenglin Wu 		if (!pad->lv_mv_type &&
668d7b5f5ccSFenglin Wu 				pad->function >= PMIC_GPIO_FUNC_INDEX_FUNC3)
669d7b5f5ccSFenglin Wu 			function += PMIC_GPIO_FUNC_INDEX_DTEST1 -
670d7b5f5ccSFenglin Wu 				PMIC_GPIO_FUNC_INDEX_FUNC3;
671eadff302SIvan T. Ivanov 
672d7b5f5ccSFenglin Wu 		if (pad->analog_pass)
673d7b5f5ccSFenglin Wu 			seq_puts(s, " analog-pass");
674d7b5f5ccSFenglin Wu 		else
675d7b5f5ccSFenglin Wu 			seq_printf(s, " %-4s",
676d7b5f5ccSFenglin Wu 					pad->output_enabled ? "out" : "in");
677d7b5f5ccSFenglin Wu 		seq_printf(s, " %-7s", pmic_gpio_functions[function]);
678eadff302SIvan T. Ivanov 		seq_printf(s, " vin-%d", pad->power_source);
679eadff302SIvan T. Ivanov 		seq_printf(s, " %-27s", biases[pad->pullup]);
680eadff302SIvan T. Ivanov 		seq_printf(s, " %-10s", buffer_types[pad->buffer_type]);
681eadff302SIvan T. Ivanov 		seq_printf(s, " %-4s", pad->out_value ? "high" : "low");
682eadff302SIvan T. Ivanov 		seq_printf(s, " %-7s", strengths[pad->strength]);
683d7b5f5ccSFenglin Wu 		seq_printf(s, " atest-%d", pad->atest);
684223463fcSFenglin Wu 		seq_printf(s, " dtest-%d", pad->dtest_buffer);
685eadff302SIvan T. Ivanov 	}
686eadff302SIvan T. Ivanov }
687eadff302SIvan T. Ivanov 
688eadff302SIvan T. Ivanov static const struct pinconf_ops pmic_gpio_pinconf_ops = {
6897382b623SSoren Brinkmann 	.is_generic			= true,
690eadff302SIvan T. Ivanov 	.pin_config_group_get		= pmic_gpio_config_get,
691eadff302SIvan T. Ivanov 	.pin_config_group_set		= pmic_gpio_config_set,
692eadff302SIvan T. Ivanov 	.pin_config_group_dbg_show	= pmic_gpio_config_dbg_show,
693eadff302SIvan T. Ivanov };
694eadff302SIvan T. Ivanov 
695eadff302SIvan T. Ivanov static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
696eadff302SIvan T. Ivanov {
697c52d9df1SLinus Walleij 	struct pmic_gpio_state *state = gpiochip_get_data(chip);
698eadff302SIvan T. Ivanov 	unsigned long config;
699eadff302SIvan T. Ivanov 
700eadff302SIvan T. Ivanov 	config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
701eadff302SIvan T. Ivanov 
702eadff302SIvan T. Ivanov 	return pmic_gpio_config_set(state->ctrl, pin, &config, 1);
703eadff302SIvan T. Ivanov }
704eadff302SIvan T. Ivanov 
705eadff302SIvan T. Ivanov static int pmic_gpio_direction_output(struct gpio_chip *chip,
706eadff302SIvan T. Ivanov 				      unsigned pin, int val)
707eadff302SIvan T. Ivanov {
708c52d9df1SLinus Walleij 	struct pmic_gpio_state *state = gpiochip_get_data(chip);
709eadff302SIvan T. Ivanov 	unsigned long config;
710eadff302SIvan T. Ivanov 
711eadff302SIvan T. Ivanov 	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
712eadff302SIvan T. Ivanov 
713eadff302SIvan T. Ivanov 	return pmic_gpio_config_set(state->ctrl, pin, &config, 1);
714eadff302SIvan T. Ivanov }
715eadff302SIvan T. Ivanov 
716eadff302SIvan T. Ivanov static int pmic_gpio_get(struct gpio_chip *chip, unsigned pin)
717eadff302SIvan T. Ivanov {
718c52d9df1SLinus Walleij 	struct pmic_gpio_state *state = gpiochip_get_data(chip);
719eadff302SIvan T. Ivanov 	struct pmic_gpio_pad *pad;
720eadff302SIvan T. Ivanov 	int ret;
721eadff302SIvan T. Ivanov 
722eadff302SIvan T. Ivanov 	pad = state->ctrl->desc->pins[pin].drv_data;
723eadff302SIvan T. Ivanov 
724eadff302SIvan T. Ivanov 	if (!pad->is_enabled)
725eadff302SIvan T. Ivanov 		return -EINVAL;
726eadff302SIvan T. Ivanov 
727eadff302SIvan T. Ivanov 	if (pad->input_enabled) {
728eadff302SIvan T. Ivanov 		ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS);
729eadff302SIvan T. Ivanov 		if (ret < 0)
730eadff302SIvan T. Ivanov 			return ret;
731eadff302SIvan T. Ivanov 
732eadff302SIvan T. Ivanov 		pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK;
733eadff302SIvan T. Ivanov 	}
734eadff302SIvan T. Ivanov 
73586c1a219SLinus Walleij 	return !!pad->out_value;
736eadff302SIvan T. Ivanov }
737eadff302SIvan T. Ivanov 
738eadff302SIvan T. Ivanov static void pmic_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
739eadff302SIvan T. Ivanov {
740c52d9df1SLinus Walleij 	struct pmic_gpio_state *state = gpiochip_get_data(chip);
741eadff302SIvan T. Ivanov 	unsigned long config;
742eadff302SIvan T. Ivanov 
743eadff302SIvan T. Ivanov 	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
744eadff302SIvan T. Ivanov 
745eadff302SIvan T. Ivanov 	pmic_gpio_config_set(state->ctrl, pin, &config, 1);
746eadff302SIvan T. Ivanov }
747eadff302SIvan T. Ivanov 
748eadff302SIvan T. Ivanov static int pmic_gpio_of_xlate(struct gpio_chip *chip,
749eadff302SIvan T. Ivanov 			      const struct of_phandle_args *gpio_desc,
750eadff302SIvan T. Ivanov 			      u32 *flags)
751eadff302SIvan T. Ivanov {
752eadff302SIvan T. Ivanov 	if (chip->of_gpio_n_cells < 2)
753eadff302SIvan T. Ivanov 		return -EINVAL;
754eadff302SIvan T. Ivanov 
755eadff302SIvan T. Ivanov 	if (flags)
756eadff302SIvan T. Ivanov 		*flags = gpio_desc->args[1];
757eadff302SIvan T. Ivanov 
758eadff302SIvan T. Ivanov 	return gpio_desc->args[0] - PMIC_GPIO_PHYSICAL_OFFSET;
759eadff302SIvan T. Ivanov }
760eadff302SIvan T. Ivanov 
761eadff302SIvan T. Ivanov static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
762eadff302SIvan T. Ivanov {
763c52d9df1SLinus Walleij 	struct pmic_gpio_state *state = gpiochip_get_data(chip);
764eadff302SIvan T. Ivanov 	struct pmic_gpio_pad *pad;
765eadff302SIvan T. Ivanov 
766eadff302SIvan T. Ivanov 	pad = state->ctrl->desc->pins[pin].drv_data;
767eadff302SIvan T. Ivanov 
768eadff302SIvan T. Ivanov 	return pad->irq;
769eadff302SIvan T. Ivanov }
770eadff302SIvan T. Ivanov 
771eadff302SIvan T. Ivanov static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
772eadff302SIvan T. Ivanov {
773c52d9df1SLinus Walleij 	struct pmic_gpio_state *state = gpiochip_get_data(chip);
774eadff302SIvan T. Ivanov 	unsigned i;
775eadff302SIvan T. Ivanov 
776eadff302SIvan T. Ivanov 	for (i = 0; i < chip->ngpio; i++) {
777eadff302SIvan T. Ivanov 		pmic_gpio_config_dbg_show(state->ctrl, s, i);
778eadff302SIvan T. Ivanov 		seq_puts(s, "\n");
779eadff302SIvan T. Ivanov 	}
780eadff302SIvan T. Ivanov }
781eadff302SIvan T. Ivanov 
782eadff302SIvan T. Ivanov static const struct gpio_chip pmic_gpio_gpio_template = {
783eadff302SIvan T. Ivanov 	.direction_input	= pmic_gpio_direction_input,
784eadff302SIvan T. Ivanov 	.direction_output	= pmic_gpio_direction_output,
785eadff302SIvan T. Ivanov 	.get			= pmic_gpio_get,
786eadff302SIvan T. Ivanov 	.set			= pmic_gpio_set,
78798c85d58SJonas Gorski 	.request		= gpiochip_generic_request,
78898c85d58SJonas Gorski 	.free			= gpiochip_generic_free,
789eadff302SIvan T. Ivanov 	.of_xlate		= pmic_gpio_of_xlate,
790eadff302SIvan T. Ivanov 	.to_irq			= pmic_gpio_to_irq,
791eadff302SIvan T. Ivanov 	.dbg_show		= pmic_gpio_dbg_show,
792eadff302SIvan T. Ivanov };
793eadff302SIvan T. Ivanov 
794eadff302SIvan T. Ivanov static int pmic_gpio_populate(struct pmic_gpio_state *state,
795eadff302SIvan T. Ivanov 			      struct pmic_gpio_pad *pad)
796eadff302SIvan T. Ivanov {
797eadff302SIvan T. Ivanov 	int type, subtype, val, dir;
798eadff302SIvan T. Ivanov 
799eadff302SIvan T. Ivanov 	type = pmic_gpio_read(state, pad, PMIC_GPIO_REG_TYPE);
800eadff302SIvan T. Ivanov 	if (type < 0)
801eadff302SIvan T. Ivanov 		return type;
802eadff302SIvan T. Ivanov 
803eadff302SIvan T. Ivanov 	if (type != PMIC_GPIO_TYPE) {
804eadff302SIvan T. Ivanov 		dev_err(state->dev, "incorrect block type 0x%x at 0x%x\n",
805eadff302SIvan T. Ivanov 			type, pad->base);
806eadff302SIvan T. Ivanov 		return -ENODEV;
807eadff302SIvan T. Ivanov 	}
808eadff302SIvan T. Ivanov 
809eadff302SIvan T. Ivanov 	subtype = pmic_gpio_read(state, pad, PMIC_GPIO_REG_SUBTYPE);
810eadff302SIvan T. Ivanov 	if (subtype < 0)
811eadff302SIvan T. Ivanov 		return subtype;
812eadff302SIvan T. Ivanov 
813eadff302SIvan T. Ivanov 	switch (subtype) {
814eadff302SIvan T. Ivanov 	case PMIC_GPIO_SUBTYPE_GPIO_4CH:
815eadff302SIvan T. Ivanov 		pad->have_buffer = true;
816eadff302SIvan T. Ivanov 	case PMIC_GPIO_SUBTYPE_GPIOC_4CH:
817eadff302SIvan T. Ivanov 		pad->num_sources = 4;
818eadff302SIvan T. Ivanov 		break;
819eadff302SIvan T. Ivanov 	case PMIC_GPIO_SUBTYPE_GPIO_8CH:
820eadff302SIvan T. Ivanov 		pad->have_buffer = true;
821eadff302SIvan T. Ivanov 	case PMIC_GPIO_SUBTYPE_GPIOC_8CH:
822eadff302SIvan T. Ivanov 		pad->num_sources = 8;
823eadff302SIvan T. Ivanov 		break;
824d7b5f5ccSFenglin Wu 	case PMIC_GPIO_SUBTYPE_GPIO_LV:
825d7b5f5ccSFenglin Wu 		pad->num_sources = 1;
826d7b5f5ccSFenglin Wu 		pad->have_buffer = true;
827d7b5f5ccSFenglin Wu 		pad->lv_mv_type = true;
828d7b5f5ccSFenglin Wu 		break;
829d7b5f5ccSFenglin Wu 	case PMIC_GPIO_SUBTYPE_GPIO_MV:
830d7b5f5ccSFenglin Wu 		pad->num_sources = 2;
831d7b5f5ccSFenglin Wu 		pad->have_buffer = true;
832d7b5f5ccSFenglin Wu 		pad->lv_mv_type = true;
833d7b5f5ccSFenglin Wu 		break;
834eadff302SIvan T. Ivanov 	default:
835eadff302SIvan T. Ivanov 		dev_err(state->dev, "unknown GPIO type 0x%x\n", subtype);
836eadff302SIvan T. Ivanov 		return -ENODEV;
837eadff302SIvan T. Ivanov 	}
838eadff302SIvan T. Ivanov 
839d7b5f5ccSFenglin Wu 	if (pad->lv_mv_type) {
840d7b5f5ccSFenglin Wu 		val = pmic_gpio_read(state, pad,
841d7b5f5ccSFenglin Wu 				PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL);
842d7b5f5ccSFenglin Wu 		if (val < 0)
843d7b5f5ccSFenglin Wu 			return val;
844d7b5f5ccSFenglin Wu 
845d7b5f5ccSFenglin Wu 		pad->out_value = !!(val & PMIC_GPIO_LV_MV_OUTPUT_INVERT);
846d7b5f5ccSFenglin Wu 		pad->function = val & PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK;
847d7b5f5ccSFenglin Wu 
848d7b5f5ccSFenglin Wu 		val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL);
849d7b5f5ccSFenglin Wu 		if (val < 0)
850d7b5f5ccSFenglin Wu 			return val;
851d7b5f5ccSFenglin Wu 
852d7b5f5ccSFenglin Wu 		dir = val & PMIC_GPIO_REG_LV_MV_MODE_DIR_MASK;
853d7b5f5ccSFenglin Wu 	} else {
854eadff302SIvan T. Ivanov 		val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL);
855eadff302SIvan T. Ivanov 		if (val < 0)
856eadff302SIvan T. Ivanov 			return val;
857eadff302SIvan T. Ivanov 
858eadff302SIvan T. Ivanov 		pad->out_value = val & PMIC_GPIO_REG_MODE_VALUE_SHIFT;
859eadff302SIvan T. Ivanov 
860eadff302SIvan T. Ivanov 		dir = val >> PMIC_GPIO_REG_MODE_DIR_SHIFT;
861eadff302SIvan T. Ivanov 		dir &= PMIC_GPIO_REG_MODE_DIR_MASK;
862d7b5f5ccSFenglin Wu 		pad->function = val >> PMIC_GPIO_REG_MODE_FUNCTION_SHIFT;
863d7b5f5ccSFenglin Wu 		pad->function &= PMIC_GPIO_REG_MODE_FUNCTION_MASK;
864d7b5f5ccSFenglin Wu 	}
865d7b5f5ccSFenglin Wu 
866eadff302SIvan T. Ivanov 	switch (dir) {
867d7b5f5ccSFenglin Wu 	case PMIC_GPIO_MODE_DIGITAL_INPUT:
868eadff302SIvan T. Ivanov 		pad->input_enabled = true;
869eadff302SIvan T. Ivanov 		pad->output_enabled = false;
870eadff302SIvan T. Ivanov 		break;
871d7b5f5ccSFenglin Wu 	case PMIC_GPIO_MODE_DIGITAL_OUTPUT:
872eadff302SIvan T. Ivanov 		pad->input_enabled = false;
873eadff302SIvan T. Ivanov 		pad->output_enabled = true;
874eadff302SIvan T. Ivanov 		break;
875d7b5f5ccSFenglin Wu 	case PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT:
876eadff302SIvan T. Ivanov 		pad->input_enabled = true;
877eadff302SIvan T. Ivanov 		pad->output_enabled = true;
878eadff302SIvan T. Ivanov 		break;
879d7b5f5ccSFenglin Wu 	case PMIC_GPIO_MODE_ANALOG_PASS_THRU:
880d7b5f5ccSFenglin Wu 		if (!pad->lv_mv_type)
881d7b5f5ccSFenglin Wu 			return -ENODEV;
882d7b5f5ccSFenglin Wu 		pad->analog_pass = true;
883d7b5f5ccSFenglin Wu 		break;
884eadff302SIvan T. Ivanov 	default:
885eadff302SIvan T. Ivanov 		dev_err(state->dev, "unknown GPIO direction\n");
886eadff302SIvan T. Ivanov 		return -ENODEV;
887eadff302SIvan T. Ivanov 	}
888eadff302SIvan T. Ivanov 
889eadff302SIvan T. Ivanov 	val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL);
890eadff302SIvan T. Ivanov 	if (val < 0)
891eadff302SIvan T. Ivanov 		return val;
892eadff302SIvan T. Ivanov 
893eadff302SIvan T. Ivanov 	pad->power_source = val >> PMIC_GPIO_REG_VIN_SHIFT;
894eadff302SIvan T. Ivanov 	pad->power_source &= PMIC_GPIO_REG_VIN_MASK;
895eadff302SIvan T. Ivanov 
896eadff302SIvan T. Ivanov 	val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_PULL_CTL);
897eadff302SIvan T. Ivanov 	if (val < 0)
898eadff302SIvan T. Ivanov 		return val;
899eadff302SIvan T. Ivanov 
900eadff302SIvan T. Ivanov 	pad->pullup = val >> PMIC_GPIO_REG_PULL_SHIFT;
901eadff302SIvan T. Ivanov 	pad->pullup &= PMIC_GPIO_REG_PULL_MASK;
902eadff302SIvan T. Ivanov 
903223463fcSFenglin Wu 	val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_IN_CTL);
904223463fcSFenglin Wu 	if (val < 0)
905223463fcSFenglin Wu 		return val;
906223463fcSFenglin Wu 
907223463fcSFenglin Wu 	if (pad->lv_mv_type && (val & PMIC_GPIO_LV_MV_DIG_IN_DTEST_EN))
908223463fcSFenglin Wu 		pad->dtest_buffer =
909223463fcSFenglin Wu 			(val & PMIC_GPIO_LV_MV_DIG_IN_DTEST_SEL_MASK) + 1;
910223463fcSFenglin Wu 	else if (!pad->lv_mv_type)
911223463fcSFenglin Wu 		pad->dtest_buffer = ffs(val);
912223463fcSFenglin Wu 	else
913223463fcSFenglin Wu 		pad->dtest_buffer = 0;
914223463fcSFenglin Wu 
915223463fcSFenglin Wu 	val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL);
916223463fcSFenglin Wu 	if (val < 0)
917223463fcSFenglin Wu 		return val;
918223463fcSFenglin Wu 
919eadff302SIvan T. Ivanov 	pad->strength = val >> PMIC_GPIO_REG_OUT_STRENGTH_SHIFT;
920eadff302SIvan T. Ivanov 	pad->strength &= PMIC_GPIO_REG_OUT_STRENGTH_MASK;
921eadff302SIvan T. Ivanov 
922eadff302SIvan T. Ivanov 	pad->buffer_type = val >> PMIC_GPIO_REG_OUT_TYPE_SHIFT;
923eadff302SIvan T. Ivanov 	pad->buffer_type &= PMIC_GPIO_REG_OUT_TYPE_MASK;
924eadff302SIvan T. Ivanov 
925d7b5f5ccSFenglin Wu 	if (pad->lv_mv_type) {
926d7b5f5ccSFenglin Wu 		val = pmic_gpio_read(state, pad,
927d7b5f5ccSFenglin Wu 				PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL);
928d7b5f5ccSFenglin Wu 		if (val < 0)
929d7b5f5ccSFenglin Wu 			return val;
930d7b5f5ccSFenglin Wu 		pad->atest = (val & PMIC_GPIO_LV_MV_ANA_MUX_SEL_MASK) + 1;
931d7b5f5ccSFenglin Wu 	}
932d7b5f5ccSFenglin Wu 
933eadff302SIvan T. Ivanov 	/* Pin could be disabled with PIN_CONFIG_BIAS_HIGH_IMPEDANCE */
934eadff302SIvan T. Ivanov 	pad->is_enabled = true;
935eadff302SIvan T. Ivanov 	return 0;
936eadff302SIvan T. Ivanov }
937eadff302SIvan T. Ivanov 
938eadff302SIvan T. Ivanov static int pmic_gpio_probe(struct platform_device *pdev)
939eadff302SIvan T. Ivanov {
940eadff302SIvan T. Ivanov 	struct device *dev = &pdev->dev;
941eadff302SIvan T. Ivanov 	struct pinctrl_pin_desc *pindesc;
942eadff302SIvan T. Ivanov 	struct pinctrl_desc *pctrldesc;
943eadff302SIvan T. Ivanov 	struct pmic_gpio_pad *pad, *pads;
944eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state;
945eadff302SIvan T. Ivanov 	int ret, npins, i;
946ab4256cfSStephen Boyd 	u32 reg;
947eadff302SIvan T. Ivanov 
948ab4256cfSStephen Boyd 	ret = of_property_read_u32(dev->of_node, "reg", &reg);
949eadff302SIvan T. Ivanov 	if (ret < 0) {
950ab4256cfSStephen Boyd 		dev_err(dev, "missing base address");
951eadff302SIvan T. Ivanov 		return ret;
952eadff302SIvan T. Ivanov 	}
953eadff302SIvan T. Ivanov 
954cfacef37SBrian Masney 	npins = (uintptr_t) device_get_match_data(&pdev->dev);
955eadff302SIvan T. Ivanov 
956eadff302SIvan T. Ivanov 	state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
957eadff302SIvan T. Ivanov 	if (!state)
958eadff302SIvan T. Ivanov 		return -ENOMEM;
959eadff302SIvan T. Ivanov 
960eadff302SIvan T. Ivanov 	platform_set_drvdata(pdev, state);
961eadff302SIvan T. Ivanov 
962eadff302SIvan T. Ivanov 	state->dev = &pdev->dev;
963eadff302SIvan T. Ivanov 	state->map = dev_get_regmap(dev->parent, NULL);
964eadff302SIvan T. Ivanov 
965eadff302SIvan T. Ivanov 	pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
966eadff302SIvan T. Ivanov 	if (!pindesc)
967eadff302SIvan T. Ivanov 		return -ENOMEM;
968eadff302SIvan T. Ivanov 
969eadff302SIvan T. Ivanov 	pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL);
970eadff302SIvan T. Ivanov 	if (!pads)
971eadff302SIvan T. Ivanov 		return -ENOMEM;
972eadff302SIvan T. Ivanov 
973eadff302SIvan T. Ivanov 	pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL);
974eadff302SIvan T. Ivanov 	if (!pctrldesc)
975eadff302SIvan T. Ivanov 		return -ENOMEM;
976eadff302SIvan T. Ivanov 
977eadff302SIvan T. Ivanov 	pctrldesc->pctlops = &pmic_gpio_pinctrl_ops;
978eadff302SIvan T. Ivanov 	pctrldesc->pmxops = &pmic_gpio_pinmux_ops;
979eadff302SIvan T. Ivanov 	pctrldesc->confops = &pmic_gpio_pinconf_ops;
980eadff302SIvan T. Ivanov 	pctrldesc->owner = THIS_MODULE;
981eadff302SIvan T. Ivanov 	pctrldesc->name = dev_name(dev);
982eadff302SIvan T. Ivanov 	pctrldesc->pins = pindesc;
983eadff302SIvan T. Ivanov 	pctrldesc->npins = npins;
984f684e4acSLinus Walleij 	pctrldesc->num_custom_params = ARRAY_SIZE(pmic_gpio_bindings);
985f684e4acSLinus Walleij 	pctrldesc->custom_params = pmic_gpio_bindings;
9864f06266aSArnd Bergmann #ifdef CONFIG_DEBUG_FS
987f684e4acSLinus Walleij 	pctrldesc->custom_conf_items = pmic_conf_items;
9884f06266aSArnd Bergmann #endif
989eadff302SIvan T. Ivanov 
990eadff302SIvan T. Ivanov 	for (i = 0; i < npins; i++, pindesc++) {
991eadff302SIvan T. Ivanov 		pad = &pads[i];
992eadff302SIvan T. Ivanov 		pindesc->drv_data = pad;
993eadff302SIvan T. Ivanov 		pindesc->number = i;
994eadff302SIvan T. Ivanov 		pindesc->name = pmic_gpio_groups[i];
995eadff302SIvan T. Ivanov 
996eadff302SIvan T. Ivanov 		pad->irq = platform_get_irq(pdev, i);
997eadff302SIvan T. Ivanov 		if (pad->irq < 0)
998eadff302SIvan T. Ivanov 			return pad->irq;
999eadff302SIvan T. Ivanov 
1000ab4256cfSStephen Boyd 		pad->base = reg + i * PMIC_GPIO_ADDRESS_RANGE;
1001eadff302SIvan T. Ivanov 
1002eadff302SIvan T. Ivanov 		ret = pmic_gpio_populate(state, pad);
1003eadff302SIvan T. Ivanov 		if (ret < 0)
1004eadff302SIvan T. Ivanov 			return ret;
1005eadff302SIvan T. Ivanov 	}
1006eadff302SIvan T. Ivanov 
1007eadff302SIvan T. Ivanov 	state->chip = pmic_gpio_gpio_template;
100858383c78SLinus Walleij 	state->chip.parent = dev;
1009eadff302SIvan T. Ivanov 	state->chip.base = -1;
1010eadff302SIvan T. Ivanov 	state->chip.ngpio = npins;
1011eadff302SIvan T. Ivanov 	state->chip.label = dev_name(dev);
1012eadff302SIvan T. Ivanov 	state->chip.of_gpio_n_cells = 2;
1013eadff302SIvan T. Ivanov 	state->chip.can_sleep = false;
1014eadff302SIvan T. Ivanov 
1015b46ddfe6SLaxman Dewangan 	state->ctrl = devm_pinctrl_register(dev, pctrldesc, state);
1016323de9efSMasahiro Yamada 	if (IS_ERR(state->ctrl))
1017323de9efSMasahiro Yamada 		return PTR_ERR(state->ctrl);
1018eadff302SIvan T. Ivanov 
1019c52d9df1SLinus Walleij 	ret = gpiochip_add_data(&state->chip, state);
1020eadff302SIvan T. Ivanov 	if (ret) {
1021eadff302SIvan T. Ivanov 		dev_err(state->dev, "can't add gpio chip\n");
1022b46ddfe6SLaxman Dewangan 		return ret;
1023eadff302SIvan T. Ivanov 	}
1024eadff302SIvan T. Ivanov 
1025149a9604SBrian Masney 	/*
1026149a9604SBrian Masney 	 * For DeviceTree-supported systems, the gpio core checks the
1027149a9604SBrian Masney 	 * pinctrl's device node for the "gpio-ranges" property.
1028149a9604SBrian Masney 	 * If it is present, it takes care of adding the pin ranges
1029149a9604SBrian Masney 	 * for the driver. In this case the driver can skip ahead.
1030149a9604SBrian Masney 	 *
1031149a9604SBrian Masney 	 * In order to remain compatible with older, existing DeviceTree
1032149a9604SBrian Masney 	 * files which don't set the "gpio-ranges" property or systems that
1033149a9604SBrian Masney 	 * utilize ACPI the driver has to call gpiochip_add_pin_range().
1034149a9604SBrian Masney 	 */
1035149a9604SBrian Masney 	if (!of_property_read_bool(dev->of_node, "gpio-ranges")) {
1036149a9604SBrian Masney 		ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0,
1037149a9604SBrian Masney 					     npins);
1038eadff302SIvan T. Ivanov 		if (ret) {
1039eadff302SIvan T. Ivanov 			dev_err(dev, "failed to add pin range\n");
1040eadff302SIvan T. Ivanov 			goto err_range;
1041eadff302SIvan T. Ivanov 		}
1042149a9604SBrian Masney 	}
1043eadff302SIvan T. Ivanov 
1044eadff302SIvan T. Ivanov 	return 0;
1045eadff302SIvan T. Ivanov 
1046eadff302SIvan T. Ivanov err_range:
1047eadff302SIvan T. Ivanov 	gpiochip_remove(&state->chip);
1048eadff302SIvan T. Ivanov 	return ret;
1049eadff302SIvan T. Ivanov }
1050eadff302SIvan T. Ivanov 
1051eadff302SIvan T. Ivanov static int pmic_gpio_remove(struct platform_device *pdev)
1052eadff302SIvan T. Ivanov {
1053eadff302SIvan T. Ivanov 	struct pmic_gpio_state *state = platform_get_drvdata(pdev);
1054eadff302SIvan T. Ivanov 
1055eadff302SIvan T. Ivanov 	gpiochip_remove(&state->chip);
1056eadff302SIvan T. Ivanov 	return 0;
1057eadff302SIvan T. Ivanov }
1058eadff302SIvan T. Ivanov 
1059eadff302SIvan T. Ivanov static const struct of_device_id pmic_gpio_of_match[] = {
1060cfacef37SBrian Masney 	{ .compatible = "qcom,pm8005-gpio", .data = (void *) 4 },
1061cfacef37SBrian Masney 	{ .compatible = "qcom,pm8916-gpio", .data = (void *) 4 },
1062cfacef37SBrian Masney 	{ .compatible = "qcom,pm8941-gpio", .data = (void *) 36 },
1063cfacef37SBrian Masney 	{ .compatible = "qcom,pm8994-gpio", .data = (void *) 22 },
1064cfacef37SBrian Masney 	{ .compatible = "qcom,pmi8994-gpio", .data = (void *) 10 },
1065cfacef37SBrian Masney 	{ .compatible = "qcom,pm8998-gpio", .data = (void *) 26 },
1066cfacef37SBrian Masney 	{ .compatible = "qcom,pmi8998-gpio", .data = (void *) 14 },
1067cfacef37SBrian Masney 	{ .compatible = "qcom,pma8084-gpio", .data = (void *) 22 },
1068cfacef37SBrian Masney 	/* pms405 has 12 GPIOs with holes on 1, 9, and 10 */
1069cfacef37SBrian Masney 	{ .compatible = "qcom,pms405-gpio", .data = (void *) 12 },
1070eadff302SIvan T. Ivanov 	{ },
1071eadff302SIvan T. Ivanov };
1072eadff302SIvan T. Ivanov 
1073eadff302SIvan T. Ivanov MODULE_DEVICE_TABLE(of, pmic_gpio_of_match);
1074eadff302SIvan T. Ivanov 
1075eadff302SIvan T. Ivanov static struct platform_driver pmic_gpio_driver = {
1076eadff302SIvan T. Ivanov 	.driver = {
1077eadff302SIvan T. Ivanov 		   .name = "qcom-spmi-gpio",
1078eadff302SIvan T. Ivanov 		   .of_match_table = pmic_gpio_of_match,
1079eadff302SIvan T. Ivanov 	},
1080eadff302SIvan T. Ivanov 	.probe	= pmic_gpio_probe,
1081eadff302SIvan T. Ivanov 	.remove = pmic_gpio_remove,
1082eadff302SIvan T. Ivanov };
1083eadff302SIvan T. Ivanov 
1084eadff302SIvan T. Ivanov module_platform_driver(pmic_gpio_driver);
1085eadff302SIvan T. Ivanov 
1086eadff302SIvan T. Ivanov MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
1087eadff302SIvan T. Ivanov MODULE_DESCRIPTION("Qualcomm SPMI PMIC GPIO pin control driver");
1088eadff302SIvan T. Ivanov MODULE_ALIAS("platform:qcom-spmi-gpio");
1089eadff302SIvan T. Ivanov MODULE_LICENSE("GPL v2");
1090