197fb5e8dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2eadff302SIvan T. Ivanov /*
3d36a9773SDavid Collins * Copyright (c) 2012-2014, 2016-2021 The Linux Foundation. All rights reserved.
44af95d09SDavid Collins * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
5eadff302SIvan T. Ivanov */
6eadff302SIvan T. Ivanov
71c5fb66aSLinus Walleij #include <linux/gpio/driver.h>
8ca69e2d1SBrian Masney #include <linux/interrupt.h>
9eadff302SIvan T. Ivanov #include <linux/module.h>
10eadff302SIvan T. Ivanov #include <linux/of.h>
11ab4256cfSStephen Boyd #include <linux/of_irq.h>
12eadff302SIvan T. Ivanov #include <linux/platform_device.h>
13eadff302SIvan T. Ivanov #include <linux/regmap.h>
14aa9430f8SAndy Shevchenko #include <linux/seq_file.h>
15eadff302SIvan T. Ivanov #include <linux/slab.h>
16d36a9773SDavid Collins #include <linux/spmi.h>
17eadff302SIvan T. Ivanov #include <linux/types.h>
18eadff302SIvan T. Ivanov
19aa9430f8SAndy Shevchenko #include <linux/pinctrl/pinconf-generic.h>
20aa9430f8SAndy Shevchenko #include <linux/pinctrl/pinconf.h>
21aa9430f8SAndy Shevchenko #include <linux/pinctrl/pinmux.h>
22aa9430f8SAndy Shevchenko
23eadff302SIvan T. Ivanov #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
24eadff302SIvan T. Ivanov
25eadff302SIvan T. Ivanov #include "../core.h"
26eadff302SIvan T. Ivanov #include "../pinctrl-utils.h"
27eadff302SIvan T. Ivanov
28eadff302SIvan T. Ivanov #define PMIC_GPIO_ADDRESS_RANGE 0x100
29eadff302SIvan T. Ivanov
30eadff302SIvan T. Ivanov /* type and subtype registers base address offsets */
31eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_TYPE 0x4
32eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_SUBTYPE 0x5
33eadff302SIvan T. Ivanov
34eadff302SIvan T. Ivanov /* GPIO peripheral type and subtype out_values */
35eadff302SIvan T. Ivanov #define PMIC_GPIO_TYPE 0x10
36eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIO_4CH 0x1
37eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIOC_4CH 0x5
38eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIO_8CH 0x9
39eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIOC_8CH 0xd
40d7b5f5ccSFenglin Wu #define PMIC_GPIO_SUBTYPE_GPIO_LV 0x10
41d7b5f5ccSFenglin Wu #define PMIC_GPIO_SUBTYPE_GPIO_MV 0x11
424af95d09SDavid Collins #define PMIC_GPIO_SUBTYPE_GPIO_LV_VIN2 0x12
434af95d09SDavid Collins #define PMIC_GPIO_SUBTYPE_GPIO_MV_VIN3 0x13
44eadff302SIvan T. Ivanov
45eadff302SIvan T. Ivanov #define PMIC_MPP_REG_RT_STS 0x10
46eadff302SIvan T. Ivanov #define PMIC_MPP_REG_RT_STS_VAL_MASK 0x1
47eadff302SIvan T. Ivanov
48eadff302SIvan T. Ivanov /* control register base address offsets */
49eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_CTL 0x40
50eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_DIG_VIN_CTL 0x41
51eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_DIG_PULL_CTL 0x42
52d7b5f5ccSFenglin Wu #define PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL 0x44
53223463fcSFenglin Wu #define PMIC_GPIO_REG_DIG_IN_CTL 0x43
54eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_DIG_OUT_CTL 0x45
55eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_EN_CTL 0x46
56d7b5f5ccSFenglin Wu #define PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL 0x4A
57eadff302SIvan T. Ivanov
58eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_MODE_CTL */
59eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_VALUE_SHIFT 0x1
60eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_FUNCTION_SHIFT 1
61eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_FUNCTION_MASK 0x7
62eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_DIR_SHIFT 4
63eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_DIR_MASK 0x7
64eadff302SIvan T. Ivanov
65d7b5f5ccSFenglin Wu #define PMIC_GPIO_MODE_DIGITAL_INPUT 0
66d7b5f5ccSFenglin Wu #define PMIC_GPIO_MODE_DIGITAL_OUTPUT 1
67d7b5f5ccSFenglin Wu #define PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT 2
68d7b5f5ccSFenglin Wu #define PMIC_GPIO_MODE_ANALOG_PASS_THRU 3
69d7b5f5ccSFenglin Wu #define PMIC_GPIO_REG_LV_MV_MODE_DIR_MASK 0x3
70d7b5f5ccSFenglin Wu
71eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_DIG_VIN_CTL */
72eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_VIN_SHIFT 0
73eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_VIN_MASK 0x7
74eadff302SIvan T. Ivanov
75eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_DIG_PULL_CTL */
76eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_PULL_SHIFT 0
77eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_PULL_MASK 0x7
78eadff302SIvan T. Ivanov
79eadff302SIvan T. Ivanov #define PMIC_GPIO_PULL_DOWN 4
80eadff302SIvan T. Ivanov #define PMIC_GPIO_PULL_DISABLE 5
81eadff302SIvan T. Ivanov
82d7b5f5ccSFenglin Wu /* PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL for LV/MV */
83d7b5f5ccSFenglin Wu #define PMIC_GPIO_LV_MV_OUTPUT_INVERT 0x80
84d7b5f5ccSFenglin Wu #define PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT 7
85d7b5f5ccSFenglin Wu #define PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK 0xF
86d7b5f5ccSFenglin Wu
87223463fcSFenglin Wu /* PMIC_GPIO_REG_DIG_IN_CTL */
88223463fcSFenglin Wu #define PMIC_GPIO_LV_MV_DIG_IN_DTEST_EN 0x80
89223463fcSFenglin Wu #define PMIC_GPIO_LV_MV_DIG_IN_DTEST_SEL_MASK 0x7
90223463fcSFenglin Wu #define PMIC_GPIO_DIG_IN_DTEST_SEL_MASK 0xf
91223463fcSFenglin Wu
92eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_DIG_OUT_CTL */
93eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_STRENGTH_SHIFT 0
94eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_STRENGTH_MASK 0x3
95eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_TYPE_SHIFT 4
96eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_TYPE_MASK 0x3
97eadff302SIvan T. Ivanov
98eadff302SIvan T. Ivanov /*
99eadff302SIvan T. Ivanov * Output type - indicates pin should be configured as push-pull,
100eadff302SIvan T. Ivanov * open drain or open source.
101eadff302SIvan T. Ivanov */
102eadff302SIvan T. Ivanov #define PMIC_GPIO_OUT_BUF_CMOS 0
103eadff302SIvan T. Ivanov #define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS 1
104eadff302SIvan T. Ivanov #define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS 2
105eadff302SIvan T. Ivanov
106723e8462SAnjelique Melendez #define PMIC_GPIO_OUT_STRENGTH_LOW 1
107723e8462SAnjelique Melendez #define PMIC_GPIO_OUT_STRENGTH_HIGH 3
108723e8462SAnjelique Melendez
109eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_EN_CTL */
110eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MASTER_EN_SHIFT 7
111eadff302SIvan T. Ivanov
112eadff302SIvan T. Ivanov #define PMIC_GPIO_PHYSICAL_OFFSET 1
113eadff302SIvan T. Ivanov
114d7b5f5ccSFenglin Wu /* PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL */
115d7b5f5ccSFenglin Wu #define PMIC_GPIO_LV_MV_ANA_MUX_SEL_MASK 0x3
116d7b5f5ccSFenglin Wu
117eadff302SIvan T. Ivanov /* Qualcomm specific pin configurations */
118eadff302SIvan T. Ivanov #define PMIC_GPIO_CONF_PULL_UP (PIN_CONFIG_END + 1)
119eadff302SIvan T. Ivanov #define PMIC_GPIO_CONF_STRENGTH (PIN_CONFIG_END + 2)
120d7b5f5ccSFenglin Wu #define PMIC_GPIO_CONF_ATEST (PIN_CONFIG_END + 3)
121d7b5f5ccSFenglin Wu #define PMIC_GPIO_CONF_ANALOG_PASS (PIN_CONFIG_END + 4)
122223463fcSFenglin Wu #define PMIC_GPIO_CONF_DTEST_BUFFER (PIN_CONFIG_END + 5)
123d7b5f5ccSFenglin Wu
124d7b5f5ccSFenglin Wu /* The index of each function in pmic_gpio_functions[] array */
125d7b5f5ccSFenglin Wu enum pmic_gpio_func_index {
126d7b5f5ccSFenglin Wu PMIC_GPIO_FUNC_INDEX_NORMAL,
127d7b5f5ccSFenglin Wu PMIC_GPIO_FUNC_INDEX_PAIRED,
128d7b5f5ccSFenglin Wu PMIC_GPIO_FUNC_INDEX_FUNC1,
129d7b5f5ccSFenglin Wu PMIC_GPIO_FUNC_INDEX_FUNC2,
130d7b5f5ccSFenglin Wu PMIC_GPIO_FUNC_INDEX_FUNC3,
131d7b5f5ccSFenglin Wu PMIC_GPIO_FUNC_INDEX_FUNC4,
132d7b5f5ccSFenglin Wu PMIC_GPIO_FUNC_INDEX_DTEST1,
133d7b5f5ccSFenglin Wu PMIC_GPIO_FUNC_INDEX_DTEST2,
134d7b5f5ccSFenglin Wu PMIC_GPIO_FUNC_INDEX_DTEST3,
135d7b5f5ccSFenglin Wu PMIC_GPIO_FUNC_INDEX_DTEST4,
136d7b5f5ccSFenglin Wu };
137eadff302SIvan T. Ivanov
138eadff302SIvan T. Ivanov /**
139eadff302SIvan T. Ivanov * struct pmic_gpio_pad - keep current GPIO settings
140eadff302SIvan T. Ivanov * @base: Address base in SPMI device.
141eadff302SIvan T. Ivanov * @is_enabled: Set to false when GPIO should be put in high Z state.
142eadff302SIvan T. Ivanov * @out_value: Cached pin output value
143eadff302SIvan T. Ivanov * @have_buffer: Set to true if GPIO output could be configured in push-pull,
144eadff302SIvan T. Ivanov * open-drain or open-source mode.
145eadff302SIvan T. Ivanov * @output_enabled: Set to true if GPIO output logic is enabled.
146eadff302SIvan T. Ivanov * @input_enabled: Set to true if GPIO input buffer logic is enabled.
147d7b5f5ccSFenglin Wu * @analog_pass: Set to true if GPIO is in analog-pass-through mode.
148d7b5f5ccSFenglin Wu * @lv_mv_type: Set to true if GPIO subtype is GPIO_LV(0x10) or GPIO_MV(0x11).
149eadff302SIvan T. Ivanov * @num_sources: Number of power-sources supported by this GPIO.
150eadff302SIvan T. Ivanov * @power_source: Current power-source used.
151eadff302SIvan T. Ivanov * @buffer_type: Push-pull, open-drain or open-source.
152eadff302SIvan T. Ivanov * @pullup: Constant current which flow trough GPIO output buffer.
153eadff302SIvan T. Ivanov * @strength: No, Low, Medium, High
154eadff302SIvan T. Ivanov * @function: See pmic_gpio_functions[]
155d7b5f5ccSFenglin Wu * @atest: the ATEST selection for GPIO analog-pass-through mode
156223463fcSFenglin Wu * @dtest_buffer: the DTEST buffer selection for digital input mode.
157eadff302SIvan T. Ivanov */
158eadff302SIvan T. Ivanov struct pmic_gpio_pad {
159eadff302SIvan T. Ivanov u16 base;
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;
182d36a9773SDavid Collins u8 usid;
183d36a9773SDavid Collins u8 pid_base;
184eadff302SIvan T. Ivanov };
185eadff302SIvan T. Ivanov
186f684e4acSLinus Walleij static const struct pinconf_generic_params pmic_gpio_bindings[] = {
1877382b623SSoren Brinkmann {"qcom,pull-up-strength", PMIC_GPIO_CONF_PULL_UP, 0},
1887382b623SSoren Brinkmann {"qcom,drive-strength", PMIC_GPIO_CONF_STRENGTH, 0},
189d7b5f5ccSFenglin Wu {"qcom,atest", PMIC_GPIO_CONF_ATEST, 0},
190d7b5f5ccSFenglin Wu {"qcom,analog-pass", PMIC_GPIO_CONF_ANALOG_PASS, 0},
191223463fcSFenglin Wu {"qcom,dtest-buffer", PMIC_GPIO_CONF_DTEST_BUFFER, 0},
192eadff302SIvan T. Ivanov };
193eadff302SIvan T. Ivanov
1944f06266aSArnd Bergmann #ifdef CONFIG_DEBUG_FS
1957382b623SSoren Brinkmann static const struct pin_config_item pmic_conf_items[ARRAY_SIZE(pmic_gpio_bindings)] = {
1967382b623SSoren Brinkmann PCONFDUMP(PMIC_GPIO_CONF_PULL_UP, "pull up strength", NULL, true),
1977382b623SSoren Brinkmann PCONFDUMP(PMIC_GPIO_CONF_STRENGTH, "drive-strength", NULL, true),
198d7b5f5ccSFenglin Wu PCONFDUMP(PMIC_GPIO_CONF_ATEST, "atest", NULL, true),
199d7b5f5ccSFenglin Wu PCONFDUMP(PMIC_GPIO_CONF_ANALOG_PASS, "analog-pass", NULL, true),
200223463fcSFenglin Wu PCONFDUMP(PMIC_GPIO_CONF_DTEST_BUFFER, "dtest-buffer", NULL, true),
201eadff302SIvan T. Ivanov };
2024f06266aSArnd Bergmann #endif
203eadff302SIvan T. Ivanov
204eadff302SIvan T. Ivanov static const char *const pmic_gpio_groups[] = {
205eadff302SIvan T. Ivanov "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", "gpio8",
206eadff302SIvan T. Ivanov "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", "gpio15",
207eadff302SIvan T. Ivanov "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", "gpio22",
208eadff302SIvan T. Ivanov "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29",
209eadff302SIvan T. Ivanov "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36",
210eadff302SIvan T. Ivanov };
211eadff302SIvan T. Ivanov
212eadff302SIvan T. Ivanov static const char *const pmic_gpio_functions[] = {
213d7b5f5ccSFenglin Wu [PMIC_GPIO_FUNC_INDEX_NORMAL] = PMIC_GPIO_FUNC_NORMAL,
214d7b5f5ccSFenglin Wu [PMIC_GPIO_FUNC_INDEX_PAIRED] = PMIC_GPIO_FUNC_PAIRED,
215d7b5f5ccSFenglin Wu [PMIC_GPIO_FUNC_INDEX_FUNC1] = PMIC_GPIO_FUNC_FUNC1,
216d7b5f5ccSFenglin Wu [PMIC_GPIO_FUNC_INDEX_FUNC2] = PMIC_GPIO_FUNC_FUNC2,
217d7b5f5ccSFenglin Wu [PMIC_GPIO_FUNC_INDEX_FUNC3] = PMIC_GPIO_FUNC_FUNC3,
218d7b5f5ccSFenglin Wu [PMIC_GPIO_FUNC_INDEX_FUNC4] = PMIC_GPIO_FUNC_FUNC4,
219d7b5f5ccSFenglin Wu [PMIC_GPIO_FUNC_INDEX_DTEST1] = PMIC_GPIO_FUNC_DTEST1,
220d7b5f5ccSFenglin Wu [PMIC_GPIO_FUNC_INDEX_DTEST2] = PMIC_GPIO_FUNC_DTEST2,
221d7b5f5ccSFenglin Wu [PMIC_GPIO_FUNC_INDEX_DTEST3] = PMIC_GPIO_FUNC_DTEST3,
222d7b5f5ccSFenglin Wu [PMIC_GPIO_FUNC_INDEX_DTEST4] = PMIC_GPIO_FUNC_DTEST4,
223eadff302SIvan T. Ivanov };
224eadff302SIvan T. Ivanov
pmic_gpio_read(struct pmic_gpio_state * state,struct pmic_gpio_pad * pad,unsigned int addr)225eadff302SIvan T. Ivanov static int pmic_gpio_read(struct pmic_gpio_state *state,
226eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad, unsigned int addr)
227eadff302SIvan T. Ivanov {
228eadff302SIvan T. Ivanov unsigned int val;
229eadff302SIvan T. Ivanov int ret;
230eadff302SIvan T. Ivanov
231eadff302SIvan T. Ivanov ret = regmap_read(state->map, pad->base + addr, &val);
232eadff302SIvan T. Ivanov if (ret < 0)
233eadff302SIvan T. Ivanov dev_err(state->dev, "read 0x%x failed\n", addr);
234eadff302SIvan T. Ivanov else
235eadff302SIvan T. Ivanov ret = val;
236eadff302SIvan T. Ivanov
237eadff302SIvan T. Ivanov return ret;
238eadff302SIvan T. Ivanov }
239eadff302SIvan T. Ivanov
pmic_gpio_write(struct pmic_gpio_state * state,struct pmic_gpio_pad * pad,unsigned int addr,unsigned int val)240eadff302SIvan T. Ivanov static int pmic_gpio_write(struct pmic_gpio_state *state,
241eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad, unsigned int addr,
242eadff302SIvan T. Ivanov unsigned int val)
243eadff302SIvan T. Ivanov {
244eadff302SIvan T. Ivanov int ret;
245eadff302SIvan T. Ivanov
246eadff302SIvan T. Ivanov ret = regmap_write(state->map, pad->base + addr, val);
247eadff302SIvan T. Ivanov if (ret < 0)
248eadff302SIvan T. Ivanov dev_err(state->dev, "write 0x%x failed\n", addr);
249eadff302SIvan T. Ivanov
250eadff302SIvan T. Ivanov return ret;
251eadff302SIvan T. Ivanov }
252eadff302SIvan T. Ivanov
pmic_gpio_get_groups_count(struct pinctrl_dev * pctldev)253eadff302SIvan T. Ivanov static int pmic_gpio_get_groups_count(struct pinctrl_dev *pctldev)
254eadff302SIvan T. Ivanov {
255eadff302SIvan T. Ivanov /* Every PIN is a group */
256eadff302SIvan T. Ivanov return pctldev->desc->npins;
257eadff302SIvan T. Ivanov }
258eadff302SIvan T. Ivanov
pmic_gpio_get_group_name(struct pinctrl_dev * pctldev,unsigned pin)259eadff302SIvan T. Ivanov static const char *pmic_gpio_get_group_name(struct pinctrl_dev *pctldev,
260eadff302SIvan T. Ivanov unsigned pin)
261eadff302SIvan T. Ivanov {
262eadff302SIvan T. Ivanov return pctldev->desc->pins[pin].name;
263eadff302SIvan T. Ivanov }
264eadff302SIvan T. Ivanov
pmic_gpio_get_group_pins(struct pinctrl_dev * pctldev,unsigned pin,const unsigned ** pins,unsigned * num_pins)265eadff302SIvan T. Ivanov static int pmic_gpio_get_group_pins(struct pinctrl_dev *pctldev, unsigned pin,
266eadff302SIvan T. Ivanov const unsigned **pins, unsigned *num_pins)
267eadff302SIvan T. Ivanov {
268eadff302SIvan T. Ivanov *pins = &pctldev->desc->pins[pin].number;
269eadff302SIvan T. Ivanov *num_pins = 1;
270eadff302SIvan T. Ivanov return 0;
271eadff302SIvan T. Ivanov }
272eadff302SIvan T. Ivanov
273eadff302SIvan T. Ivanov static const struct pinctrl_ops pmic_gpio_pinctrl_ops = {
274eadff302SIvan T. Ivanov .get_groups_count = pmic_gpio_get_groups_count,
275eadff302SIvan T. Ivanov .get_group_name = pmic_gpio_get_group_name,
276eadff302SIvan T. Ivanov .get_group_pins = pmic_gpio_get_group_pins,
2777382b623SSoren Brinkmann .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
278d32f7fd3SIrina Tirdea .dt_free_map = pinctrl_utils_free_map,
279eadff302SIvan T. Ivanov };
280eadff302SIvan T. Ivanov
pmic_gpio_get_functions_count(struct pinctrl_dev * pctldev)281eadff302SIvan T. Ivanov static int pmic_gpio_get_functions_count(struct pinctrl_dev *pctldev)
282eadff302SIvan T. Ivanov {
283eadff302SIvan T. Ivanov return ARRAY_SIZE(pmic_gpio_functions);
284eadff302SIvan T. Ivanov }
285eadff302SIvan T. Ivanov
pmic_gpio_get_function_name(struct pinctrl_dev * pctldev,unsigned function)286eadff302SIvan T. Ivanov static const char *pmic_gpio_get_function_name(struct pinctrl_dev *pctldev,
287eadff302SIvan T. Ivanov unsigned function)
288eadff302SIvan T. Ivanov {
289eadff302SIvan T. Ivanov return pmic_gpio_functions[function];
290eadff302SIvan T. Ivanov }
291eadff302SIvan T. Ivanov
pmic_gpio_get_function_groups(struct pinctrl_dev * pctldev,unsigned function,const char * const ** groups,unsigned * const num_qgroups)292eadff302SIvan T. Ivanov static int pmic_gpio_get_function_groups(struct pinctrl_dev *pctldev,
293eadff302SIvan T. Ivanov unsigned function,
294eadff302SIvan T. Ivanov const char *const **groups,
295eadff302SIvan T. Ivanov unsigned *const num_qgroups)
296eadff302SIvan T. Ivanov {
297eadff302SIvan T. Ivanov *groups = pmic_gpio_groups;
298eadff302SIvan T. Ivanov *num_qgroups = pctldev->desc->npins;
299eadff302SIvan T. Ivanov return 0;
300eadff302SIvan T. Ivanov }
301eadff302SIvan T. Ivanov
pmic_gpio_set_mux(struct pinctrl_dev * pctldev,unsigned function,unsigned pin)302eadff302SIvan T. Ivanov static int pmic_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned function,
303eadff302SIvan T. Ivanov unsigned pin)
304eadff302SIvan T. Ivanov {
305eadff302SIvan T. Ivanov struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev);
306eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad;
307eadff302SIvan T. Ivanov unsigned int val;
308eadff302SIvan T. Ivanov int ret;
309eadff302SIvan T. Ivanov
310d7b5f5ccSFenglin Wu if (function > PMIC_GPIO_FUNC_INDEX_DTEST4) {
311d7b5f5ccSFenglin Wu pr_err("function: %d is not defined\n", function);
312d7b5f5ccSFenglin Wu return -EINVAL;
313d7b5f5ccSFenglin Wu }
314d7b5f5ccSFenglin Wu
315eadff302SIvan T. Ivanov pad = pctldev->desc->pins[pin].drv_data;
316d7b5f5ccSFenglin Wu /*
317d7b5f5ccSFenglin Wu * Non-LV/MV subtypes only support 2 special functions,
318d7b5f5ccSFenglin Wu * offsetting the dtestx function values by 2
319d7b5f5ccSFenglin Wu */
320d7b5f5ccSFenglin Wu if (!pad->lv_mv_type) {
321d7b5f5ccSFenglin Wu if (function == PMIC_GPIO_FUNC_INDEX_FUNC3 ||
322d7b5f5ccSFenglin Wu function == PMIC_GPIO_FUNC_INDEX_FUNC4) {
323d7b5f5ccSFenglin Wu pr_err("LV/MV subtype doesn't have func3/func4\n");
324d7b5f5ccSFenglin Wu return -EINVAL;
325d7b5f5ccSFenglin Wu }
326d7b5f5ccSFenglin Wu if (function >= PMIC_GPIO_FUNC_INDEX_DTEST1)
327d7b5f5ccSFenglin Wu function -= (PMIC_GPIO_FUNC_INDEX_DTEST1 -
328d7b5f5ccSFenglin Wu PMIC_GPIO_FUNC_INDEX_FUNC3);
329d7b5f5ccSFenglin Wu }
330eadff302SIvan T. Ivanov
331eadff302SIvan T. Ivanov pad->function = function;
332eadff302SIvan T. Ivanov
333d7b5f5ccSFenglin Wu if (pad->analog_pass)
334d7b5f5ccSFenglin Wu val = PMIC_GPIO_MODE_ANALOG_PASS_THRU;
335d7b5f5ccSFenglin Wu else if (pad->output_enabled && pad->input_enabled)
336d7b5f5ccSFenglin Wu val = PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT;
337d7b5f5ccSFenglin Wu else if (pad->output_enabled)
338d7b5f5ccSFenglin Wu val = PMIC_GPIO_MODE_DIGITAL_OUTPUT;
339eadff302SIvan T. Ivanov else
340d7b5f5ccSFenglin Wu val = PMIC_GPIO_MODE_DIGITAL_INPUT;
341eadff302SIvan T. Ivanov
342d7b5f5ccSFenglin Wu if (pad->lv_mv_type) {
343d7b5f5ccSFenglin Wu ret = pmic_gpio_write(state, pad,
344d7b5f5ccSFenglin Wu PMIC_GPIO_REG_MODE_CTL, val);
345d7b5f5ccSFenglin Wu if (ret < 0)
346d7b5f5ccSFenglin Wu return ret;
347d7b5f5ccSFenglin Wu
348d7b5f5ccSFenglin Wu val = pad->atest - 1;
349d7b5f5ccSFenglin Wu ret = pmic_gpio_write(state, pad,
350d7b5f5ccSFenglin Wu PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL, val);
351d7b5f5ccSFenglin Wu if (ret < 0)
352d7b5f5ccSFenglin Wu return ret;
353d7b5f5ccSFenglin Wu
354d7b5f5ccSFenglin Wu val = pad->out_value
355d7b5f5ccSFenglin Wu << PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT;
356d7b5f5ccSFenglin Wu val |= pad->function
357d7b5f5ccSFenglin Wu & PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK;
358d7b5f5ccSFenglin Wu ret = pmic_gpio_write(state, pad,
359d7b5f5ccSFenglin Wu PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL, val);
360d7b5f5ccSFenglin Wu if (ret < 0)
361d7b5f5ccSFenglin Wu return ret;
362d7b5f5ccSFenglin Wu } else {
363dc391502SIvan T. Ivanov val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT;
364eadff302SIvan T. Ivanov val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT;
365eadff302SIvan T. Ivanov val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT;
366eadff302SIvan T. Ivanov
367eadff302SIvan T. Ivanov ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val);
368eadff302SIvan T. Ivanov if (ret < 0)
369eadff302SIvan T. Ivanov return ret;
370d7b5f5ccSFenglin Wu }
371eadff302SIvan T. Ivanov
372eadff302SIvan T. Ivanov val = pad->is_enabled << PMIC_GPIO_REG_MASTER_EN_SHIFT;
373eadff302SIvan T. Ivanov
374eadff302SIvan T. Ivanov return pmic_gpio_write(state, pad, PMIC_GPIO_REG_EN_CTL, val);
375eadff302SIvan T. Ivanov }
376eadff302SIvan T. Ivanov
377eadff302SIvan T. Ivanov static const struct pinmux_ops pmic_gpio_pinmux_ops = {
378eadff302SIvan T. Ivanov .get_functions_count = pmic_gpio_get_functions_count,
379eadff302SIvan T. Ivanov .get_function_name = pmic_gpio_get_function_name,
380eadff302SIvan T. Ivanov .get_function_groups = pmic_gpio_get_function_groups,
381eadff302SIvan T. Ivanov .set_mux = pmic_gpio_set_mux,
382eadff302SIvan T. Ivanov };
383eadff302SIvan T. Ivanov
pmic_gpio_config_get(struct pinctrl_dev * pctldev,unsigned int pin,unsigned long * config)384eadff302SIvan T. Ivanov static int pmic_gpio_config_get(struct pinctrl_dev *pctldev,
385eadff302SIvan T. Ivanov unsigned int pin, unsigned long *config)
386eadff302SIvan T. Ivanov {
387eadff302SIvan T. Ivanov unsigned param = pinconf_to_config_param(*config);
388eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad;
389eadff302SIvan T. Ivanov unsigned arg;
390eadff302SIvan T. Ivanov
391eadff302SIvan T. Ivanov pad = pctldev->desc->pins[pin].drv_data;
392eadff302SIvan T. Ivanov
393eadff302SIvan T. Ivanov switch (param) {
394eadff302SIvan T. Ivanov case PIN_CONFIG_DRIVE_PUSH_PULL:
3951cf86bc2SDouglas Anderson if (pad->buffer_type != PMIC_GPIO_OUT_BUF_CMOS)
3961cf86bc2SDouglas Anderson return -EINVAL;
3971cf86bc2SDouglas Anderson arg = 1;
398eadff302SIvan T. Ivanov break;
399eadff302SIvan T. Ivanov case PIN_CONFIG_DRIVE_OPEN_DRAIN:
4001cf86bc2SDouglas Anderson if (pad->buffer_type != PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS)
4011cf86bc2SDouglas Anderson return -EINVAL;
4021cf86bc2SDouglas Anderson arg = 1;
403eadff302SIvan T. Ivanov break;
404eadff302SIvan T. Ivanov case PIN_CONFIG_DRIVE_OPEN_SOURCE:
4051cf86bc2SDouglas Anderson if (pad->buffer_type != PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS)
4061cf86bc2SDouglas Anderson return -EINVAL;
4071cf86bc2SDouglas Anderson arg = 1;
408eadff302SIvan T. Ivanov break;
409eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_PULL_DOWN:
4101cf86bc2SDouglas Anderson if (pad->pullup != PMIC_GPIO_PULL_DOWN)
4111cf86bc2SDouglas Anderson return -EINVAL;
4121cf86bc2SDouglas Anderson arg = 1;
413eadff302SIvan T. Ivanov break;
414eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_DISABLE:
4151cf86bc2SDouglas Anderson if (pad->pullup != PMIC_GPIO_PULL_DISABLE)
4161cf86bc2SDouglas Anderson return -EINVAL;
4171cf86bc2SDouglas Anderson arg = 1;
418eadff302SIvan T. Ivanov break;
419eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_PULL_UP:
4201cf86bc2SDouglas Anderson if (pad->pullup != PMIC_GPIO_PULL_UP_30)
4211cf86bc2SDouglas Anderson return -EINVAL;
4221cf86bc2SDouglas Anderson arg = 1;
423eadff302SIvan T. Ivanov break;
424eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
4251cf86bc2SDouglas Anderson if (pad->is_enabled)
4261cf86bc2SDouglas Anderson return -EINVAL;
4271cf86bc2SDouglas Anderson arg = 1;
428eadff302SIvan T. Ivanov break;
429eadff302SIvan T. Ivanov case PIN_CONFIG_POWER_SOURCE:
430eadff302SIvan T. Ivanov arg = pad->power_source;
431eadff302SIvan T. Ivanov break;
432eadff302SIvan T. Ivanov case PIN_CONFIG_INPUT_ENABLE:
4331cf86bc2SDouglas Anderson if (!pad->input_enabled)
4341cf86bc2SDouglas Anderson return -EINVAL;
4351cf86bc2SDouglas Anderson arg = 1;
436eadff302SIvan T. Ivanov break;
437727293a8SSubbaraman Narayanamurthy case PIN_CONFIG_OUTPUT_ENABLE:
438727293a8SSubbaraman Narayanamurthy arg = pad->output_enabled;
439727293a8SSubbaraman Narayanamurthy break;
440eadff302SIvan T. Ivanov case PIN_CONFIG_OUTPUT:
441eadff302SIvan T. Ivanov arg = pad->out_value;
442eadff302SIvan T. Ivanov break;
443eadff302SIvan T. Ivanov case PMIC_GPIO_CONF_PULL_UP:
444eadff302SIvan T. Ivanov arg = pad->pullup;
445eadff302SIvan T. Ivanov break;
446eadff302SIvan T. Ivanov case PMIC_GPIO_CONF_STRENGTH:
447723e8462SAnjelique Melendez switch (pad->strength) {
448723e8462SAnjelique Melendez case PMIC_GPIO_OUT_STRENGTH_HIGH:
449723e8462SAnjelique Melendez arg = PMIC_GPIO_STRENGTH_HIGH;
450723e8462SAnjelique Melendez break;
451723e8462SAnjelique Melendez case PMIC_GPIO_OUT_STRENGTH_LOW:
452723e8462SAnjelique Melendez arg = PMIC_GPIO_STRENGTH_LOW;
453723e8462SAnjelique Melendez break;
454723e8462SAnjelique Melendez default:
455eadff302SIvan T. Ivanov arg = pad->strength;
456eadff302SIvan T. Ivanov break;
457723e8462SAnjelique Melendez }
458723e8462SAnjelique Melendez break;
459d7b5f5ccSFenglin Wu case PMIC_GPIO_CONF_ATEST:
460d7b5f5ccSFenglin Wu arg = pad->atest;
461d7b5f5ccSFenglin Wu break;
462d7b5f5ccSFenglin Wu case PMIC_GPIO_CONF_ANALOG_PASS:
463d7b5f5ccSFenglin Wu arg = pad->analog_pass;
464d7b5f5ccSFenglin Wu break;
465223463fcSFenglin Wu case PMIC_GPIO_CONF_DTEST_BUFFER:
466223463fcSFenglin Wu arg = pad->dtest_buffer;
467223463fcSFenglin Wu break;
468eadff302SIvan T. Ivanov default:
469eadff302SIvan T. Ivanov return -EINVAL;
470eadff302SIvan T. Ivanov }
471eadff302SIvan T. Ivanov
472eadff302SIvan T. Ivanov *config = pinconf_to_config_packed(param, arg);
473eadff302SIvan T. Ivanov return 0;
474eadff302SIvan T. Ivanov }
475eadff302SIvan T. Ivanov
pmic_gpio_config_set(struct pinctrl_dev * pctldev,unsigned int pin,unsigned long * configs,unsigned nconfs)476eadff302SIvan T. Ivanov static int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
477eadff302SIvan T. Ivanov unsigned long *configs, unsigned nconfs)
478eadff302SIvan T. Ivanov {
479eadff302SIvan T. Ivanov struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev);
480eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad;
481eadff302SIvan T. Ivanov unsigned param, arg;
482eadff302SIvan T. Ivanov unsigned int val;
483eadff302SIvan T. Ivanov int i, ret;
484eadff302SIvan T. Ivanov
485eadff302SIvan T. Ivanov pad = pctldev->desc->pins[pin].drv_data;
486eadff302SIvan T. Ivanov
4876cb74f44SFenglin Wu pad->is_enabled = true;
488eadff302SIvan T. Ivanov for (i = 0; i < nconfs; i++) {
489eadff302SIvan T. Ivanov param = pinconf_to_config_param(configs[i]);
490eadff302SIvan T. Ivanov arg = pinconf_to_config_argument(configs[i]);
491eadff302SIvan T. Ivanov
492eadff302SIvan T. Ivanov switch (param) {
493eadff302SIvan T. Ivanov case PIN_CONFIG_DRIVE_PUSH_PULL:
494eadff302SIvan T. Ivanov pad->buffer_type = PMIC_GPIO_OUT_BUF_CMOS;
495eadff302SIvan T. Ivanov break;
496eadff302SIvan T. Ivanov case PIN_CONFIG_DRIVE_OPEN_DRAIN:
497eadff302SIvan T. Ivanov if (!pad->have_buffer)
498eadff302SIvan T. Ivanov return -EINVAL;
499eadff302SIvan T. Ivanov pad->buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS;
500eadff302SIvan T. Ivanov break;
501eadff302SIvan T. Ivanov case PIN_CONFIG_DRIVE_OPEN_SOURCE:
502eadff302SIvan T. Ivanov if (!pad->have_buffer)
503eadff302SIvan T. Ivanov return -EINVAL;
504eadff302SIvan T. Ivanov pad->buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS;
505eadff302SIvan T. Ivanov break;
506eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_DISABLE:
507eadff302SIvan T. Ivanov pad->pullup = PMIC_GPIO_PULL_DISABLE;
508eadff302SIvan T. Ivanov break;
509eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_PULL_UP:
510eadff302SIvan T. Ivanov pad->pullup = PMIC_GPIO_PULL_UP_30;
511eadff302SIvan T. Ivanov break;
512eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_PULL_DOWN:
513eadff302SIvan T. Ivanov if (arg)
514eadff302SIvan T. Ivanov pad->pullup = PMIC_GPIO_PULL_DOWN;
515eadff302SIvan T. Ivanov else
516eadff302SIvan T. Ivanov pad->pullup = PMIC_GPIO_PULL_DISABLE;
517eadff302SIvan T. Ivanov break;
518eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
519eadff302SIvan T. Ivanov pad->is_enabled = false;
520eadff302SIvan T. Ivanov break;
521eadff302SIvan T. Ivanov case PIN_CONFIG_POWER_SOURCE:
5224e83ac4cSFenglin Wu if (arg >= pad->num_sources)
523eadff302SIvan T. Ivanov return -EINVAL;
524eadff302SIvan T. Ivanov pad->power_source = arg;
525eadff302SIvan T. Ivanov break;
526eadff302SIvan T. Ivanov case PIN_CONFIG_INPUT_ENABLE:
527eadff302SIvan T. Ivanov pad->input_enabled = arg ? true : false;
528eadff302SIvan T. Ivanov break;
529727293a8SSubbaraman Narayanamurthy case PIN_CONFIG_OUTPUT_ENABLE:
530727293a8SSubbaraman Narayanamurthy pad->output_enabled = arg ? true : false;
531727293a8SSubbaraman Narayanamurthy break;
532eadff302SIvan T. Ivanov case PIN_CONFIG_OUTPUT:
533eadff302SIvan T. Ivanov pad->output_enabled = true;
534eadff302SIvan T. Ivanov pad->out_value = arg;
535eadff302SIvan T. Ivanov break;
536eadff302SIvan T. Ivanov case PMIC_GPIO_CONF_PULL_UP:
537eadff302SIvan T. Ivanov if (arg > PMIC_GPIO_PULL_UP_1P5_30)
538eadff302SIvan T. Ivanov return -EINVAL;
539eadff302SIvan T. Ivanov pad->pullup = arg;
540eadff302SIvan T. Ivanov break;
541eadff302SIvan T. Ivanov case PMIC_GPIO_CONF_STRENGTH:
542eadff302SIvan T. Ivanov if (arg > PMIC_GPIO_STRENGTH_LOW)
543eadff302SIvan T. Ivanov return -EINVAL;
544723e8462SAnjelique Melendez switch (arg) {
545723e8462SAnjelique Melendez case PMIC_GPIO_STRENGTH_HIGH:
546723e8462SAnjelique Melendez pad->strength = PMIC_GPIO_OUT_STRENGTH_HIGH;
547723e8462SAnjelique Melendez break;
548723e8462SAnjelique Melendez case PMIC_GPIO_STRENGTH_LOW:
549723e8462SAnjelique Melendez pad->strength = PMIC_GPIO_OUT_STRENGTH_LOW;
550723e8462SAnjelique Melendez break;
551723e8462SAnjelique Melendez default:
552eadff302SIvan T. Ivanov pad->strength = arg;
553eadff302SIvan T. Ivanov break;
554723e8462SAnjelique Melendez }
555723e8462SAnjelique Melendez break;
556d7b5f5ccSFenglin Wu case PMIC_GPIO_CONF_ATEST:
557d7b5f5ccSFenglin Wu if (!pad->lv_mv_type || arg > 4)
558d7b5f5ccSFenglin Wu return -EINVAL;
559d7b5f5ccSFenglin Wu pad->atest = arg;
560d7b5f5ccSFenglin Wu break;
561d7b5f5ccSFenglin Wu case PMIC_GPIO_CONF_ANALOG_PASS:
562d7b5f5ccSFenglin Wu if (!pad->lv_mv_type)
563d7b5f5ccSFenglin Wu return -EINVAL;
564d7b5f5ccSFenglin Wu pad->analog_pass = true;
565d7b5f5ccSFenglin Wu break;
566223463fcSFenglin Wu case PMIC_GPIO_CONF_DTEST_BUFFER:
567223463fcSFenglin Wu if (arg > 4)
568223463fcSFenglin Wu return -EINVAL;
569223463fcSFenglin Wu pad->dtest_buffer = arg;
570223463fcSFenglin Wu break;
571eadff302SIvan T. Ivanov default:
572eadff302SIvan T. Ivanov return -EINVAL;
573eadff302SIvan T. Ivanov }
574eadff302SIvan T. Ivanov }
575eadff302SIvan T. Ivanov
576eadff302SIvan T. Ivanov val = pad->power_source << PMIC_GPIO_REG_VIN_SHIFT;
577eadff302SIvan T. Ivanov
578eadff302SIvan T. Ivanov ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL, val);
579eadff302SIvan T. Ivanov if (ret < 0)
580eadff302SIvan T. Ivanov return ret;
581eadff302SIvan T. Ivanov
582eadff302SIvan T. Ivanov val = pad->pullup << PMIC_GPIO_REG_PULL_SHIFT;
583eadff302SIvan T. Ivanov
584eadff302SIvan T. Ivanov ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_PULL_CTL, val);
585eadff302SIvan T. Ivanov if (ret < 0)
586eadff302SIvan T. Ivanov return ret;
587eadff302SIvan T. Ivanov
588eadff302SIvan T. Ivanov val = pad->buffer_type << PMIC_GPIO_REG_OUT_TYPE_SHIFT;
589982df6aeSIvan T. Ivanov val |= pad->strength << PMIC_GPIO_REG_OUT_STRENGTH_SHIFT;
590eadff302SIvan T. Ivanov
591eadff302SIvan T. Ivanov ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL, val);
592eadff302SIvan T. Ivanov if (ret < 0)
593eadff302SIvan T. Ivanov return ret;
594eadff302SIvan T. Ivanov
595223463fcSFenglin Wu if (pad->dtest_buffer == 0) {
596223463fcSFenglin Wu val = 0;
597223463fcSFenglin Wu } else {
598223463fcSFenglin Wu if (pad->lv_mv_type) {
599223463fcSFenglin Wu val = pad->dtest_buffer - 1;
600223463fcSFenglin Wu val |= PMIC_GPIO_LV_MV_DIG_IN_DTEST_EN;
601223463fcSFenglin Wu } else {
602223463fcSFenglin Wu val = BIT(pad->dtest_buffer - 1);
603223463fcSFenglin Wu }
604223463fcSFenglin Wu }
605223463fcSFenglin Wu ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_IN_CTL, val);
606223463fcSFenglin Wu if (ret < 0)
607223463fcSFenglin Wu return ret;
608223463fcSFenglin Wu
609d7b5f5ccSFenglin Wu if (pad->analog_pass)
610d7b5f5ccSFenglin Wu val = PMIC_GPIO_MODE_ANALOG_PASS_THRU;
611d7b5f5ccSFenglin Wu else if (pad->output_enabled && pad->input_enabled)
612d7b5f5ccSFenglin Wu val = PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT;
613d7b5f5ccSFenglin Wu else if (pad->output_enabled)
614d7b5f5ccSFenglin Wu val = PMIC_GPIO_MODE_DIGITAL_OUTPUT;
615eadff302SIvan T. Ivanov else
616d7b5f5ccSFenglin Wu val = PMIC_GPIO_MODE_DIGITAL_INPUT;
617eadff302SIvan T. Ivanov
618d7b5f5ccSFenglin Wu if (pad->lv_mv_type) {
619d7b5f5ccSFenglin Wu ret = pmic_gpio_write(state, pad,
620d7b5f5ccSFenglin Wu PMIC_GPIO_REG_MODE_CTL, val);
621d7b5f5ccSFenglin Wu if (ret < 0)
622d7b5f5ccSFenglin Wu return ret;
623d7b5f5ccSFenglin Wu
624d7b5f5ccSFenglin Wu val = pad->atest - 1;
625d7b5f5ccSFenglin Wu ret = pmic_gpio_write(state, pad,
626d7b5f5ccSFenglin Wu PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL, val);
627d7b5f5ccSFenglin Wu if (ret < 0)
628d7b5f5ccSFenglin Wu return ret;
629d7b5f5ccSFenglin Wu
630d7b5f5ccSFenglin Wu val = pad->out_value
631d7b5f5ccSFenglin Wu << PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT;
632d7b5f5ccSFenglin Wu val |= pad->function
633d7b5f5ccSFenglin Wu & PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK;
634d7b5f5ccSFenglin Wu ret = pmic_gpio_write(state, pad,
635d7b5f5ccSFenglin Wu PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL, val);
636d7b5f5ccSFenglin Wu if (ret < 0)
637d7b5f5ccSFenglin Wu return ret;
638d7b5f5ccSFenglin Wu } else {
639eadff302SIvan T. Ivanov val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT;
640eadff302SIvan T. Ivanov val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT;
641eadff302SIvan T. Ivanov val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT;
642eadff302SIvan T. Ivanov
643d7b5f5ccSFenglin Wu ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val);
644d7b5f5ccSFenglin Wu if (ret < 0)
645d7b5f5ccSFenglin Wu return ret;
646d7b5f5ccSFenglin Wu }
647d7b5f5ccSFenglin Wu
6486cb74f44SFenglin Wu val = pad->is_enabled << PMIC_GPIO_REG_MASTER_EN_SHIFT;
6496cb74f44SFenglin Wu
6506cb74f44SFenglin Wu ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_EN_CTL, val);
6516cb74f44SFenglin Wu
652d7b5f5ccSFenglin Wu return ret;
653eadff302SIvan T. Ivanov }
654eadff302SIvan T. Ivanov
pmic_gpio_config_dbg_show(struct pinctrl_dev * pctldev,struct seq_file * s,unsigned pin)655eadff302SIvan T. Ivanov static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev,
656eadff302SIvan T. Ivanov struct seq_file *s, unsigned pin)
657eadff302SIvan T. Ivanov {
658eadff302SIvan T. Ivanov struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev);
659eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad;
660d7b5f5ccSFenglin Wu int ret, val, function;
661eadff302SIvan T. Ivanov
662eadff302SIvan T. Ivanov static const char *const biases[] = {
663eadff302SIvan T. Ivanov "pull-up 30uA", "pull-up 1.5uA", "pull-up 31.5uA",
664eadff302SIvan T. Ivanov "pull-up 1.5uA + 30uA boost", "pull-down 10uA", "no pull"
665eadff302SIvan T. Ivanov };
666eadff302SIvan T. Ivanov static const char *const buffer_types[] = {
667eadff302SIvan T. Ivanov "push-pull", "open-drain", "open-source"
668eadff302SIvan T. Ivanov };
669eadff302SIvan T. Ivanov static const char *const strengths[] = {
670eadff302SIvan T. Ivanov "no", "high", "medium", "low"
671eadff302SIvan T. Ivanov };
672eadff302SIvan T. Ivanov
673eadff302SIvan T. Ivanov pad = pctldev->desc->pins[pin].drv_data;
674eadff302SIvan T. Ivanov
675eadff302SIvan T. Ivanov seq_printf(s, " gpio%-2d:", pin + PMIC_GPIO_PHYSICAL_OFFSET);
676eadff302SIvan T. Ivanov
677eadff302SIvan T. Ivanov val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_EN_CTL);
678eadff302SIvan T. Ivanov
679eadff302SIvan T. Ivanov if (val < 0 || !(val >> PMIC_GPIO_REG_MASTER_EN_SHIFT)) {
680eadff302SIvan T. Ivanov seq_puts(s, " ---");
681eadff302SIvan T. Ivanov } else {
68224a66618SIvan T. Ivanov if (pad->input_enabled) {
683eadff302SIvan T. Ivanov ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS);
68424a66618SIvan T. Ivanov if (ret < 0)
68524a66618SIvan T. Ivanov return;
68624a66618SIvan T. Ivanov
687eadff302SIvan T. Ivanov ret &= PMIC_MPP_REG_RT_STS_VAL_MASK;
688eadff302SIvan T. Ivanov pad->out_value = ret;
689eadff302SIvan T. Ivanov }
690d7b5f5ccSFenglin Wu /*
691d7b5f5ccSFenglin Wu * For the non-LV/MV subtypes only 2 special functions are
692d7b5f5ccSFenglin Wu * available, offsetting the dtest function values by 2.
693d7b5f5ccSFenglin Wu */
694d7b5f5ccSFenglin Wu function = pad->function;
695d7b5f5ccSFenglin Wu if (!pad->lv_mv_type &&
696d7b5f5ccSFenglin Wu pad->function >= PMIC_GPIO_FUNC_INDEX_FUNC3)
697d7b5f5ccSFenglin Wu function += PMIC_GPIO_FUNC_INDEX_DTEST1 -
698d7b5f5ccSFenglin Wu PMIC_GPIO_FUNC_INDEX_FUNC3;
699eadff302SIvan T. Ivanov
700d7b5f5ccSFenglin Wu if (pad->analog_pass)
701d7b5f5ccSFenglin Wu seq_puts(s, " analog-pass");
702d7b5f5ccSFenglin Wu else
703d7b5f5ccSFenglin Wu seq_printf(s, " %-4s",
704d7b5f5ccSFenglin Wu pad->output_enabled ? "out" : "in");
705202ba5ebSBjorn Andersson seq_printf(s, " %-4s", pad->out_value ? "high" : "low");
706d7b5f5ccSFenglin Wu seq_printf(s, " %-7s", pmic_gpio_functions[function]);
707eadff302SIvan T. Ivanov seq_printf(s, " vin-%d", pad->power_source);
708eadff302SIvan T. Ivanov seq_printf(s, " %-27s", biases[pad->pullup]);
709eadff302SIvan T. Ivanov seq_printf(s, " %-10s", buffer_types[pad->buffer_type]);
710eadff302SIvan T. Ivanov seq_printf(s, " %-7s", strengths[pad->strength]);
711d7b5f5ccSFenglin Wu seq_printf(s, " atest-%d", pad->atest);
712223463fcSFenglin Wu seq_printf(s, " dtest-%d", pad->dtest_buffer);
713eadff302SIvan T. Ivanov }
714eadff302SIvan T. Ivanov }
715eadff302SIvan T. Ivanov
716eadff302SIvan T. Ivanov static const struct pinconf_ops pmic_gpio_pinconf_ops = {
7177382b623SSoren Brinkmann .is_generic = true,
718eadff302SIvan T. Ivanov .pin_config_group_get = pmic_gpio_config_get,
719eadff302SIvan T. Ivanov .pin_config_group_set = pmic_gpio_config_set,
720eadff302SIvan T. Ivanov .pin_config_group_dbg_show = pmic_gpio_config_dbg_show,
721eadff302SIvan T. Ivanov };
722eadff302SIvan T. Ivanov
pmic_gpio_direction_input(struct gpio_chip * chip,unsigned pin)723eadff302SIvan T. Ivanov static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
724eadff302SIvan T. Ivanov {
725c52d9df1SLinus Walleij struct pmic_gpio_state *state = gpiochip_get_data(chip);
726eadff302SIvan T. Ivanov unsigned long config;
727eadff302SIvan T. Ivanov
728eadff302SIvan T. Ivanov config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
729eadff302SIvan T. Ivanov
730eadff302SIvan T. Ivanov return pmic_gpio_config_set(state->ctrl, pin, &config, 1);
731eadff302SIvan T. Ivanov }
732eadff302SIvan T. Ivanov
pmic_gpio_direction_output(struct gpio_chip * chip,unsigned pin,int val)733eadff302SIvan T. Ivanov static int pmic_gpio_direction_output(struct gpio_chip *chip,
734eadff302SIvan T. Ivanov unsigned pin, int val)
735eadff302SIvan T. Ivanov {
736c52d9df1SLinus Walleij struct pmic_gpio_state *state = gpiochip_get_data(chip);
737eadff302SIvan T. Ivanov unsigned long config;
738eadff302SIvan T. Ivanov
739eadff302SIvan T. Ivanov config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
740eadff302SIvan T. Ivanov
741eadff302SIvan T. Ivanov return pmic_gpio_config_set(state->ctrl, pin, &config, 1);
742eadff302SIvan T. Ivanov }
743eadff302SIvan T. Ivanov
pmic_gpio_get(struct gpio_chip * chip,unsigned pin)744eadff302SIvan T. Ivanov static int pmic_gpio_get(struct gpio_chip *chip, unsigned pin)
745eadff302SIvan T. Ivanov {
746c52d9df1SLinus Walleij struct pmic_gpio_state *state = gpiochip_get_data(chip);
747eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad;
748eadff302SIvan T. Ivanov int ret;
749eadff302SIvan T. Ivanov
750eadff302SIvan T. Ivanov pad = state->ctrl->desc->pins[pin].drv_data;
751eadff302SIvan T. Ivanov
752eadff302SIvan T. Ivanov if (!pad->is_enabled)
753eadff302SIvan T. Ivanov return -EINVAL;
754eadff302SIvan T. Ivanov
755eadff302SIvan T. Ivanov if (pad->input_enabled) {
756eadff302SIvan T. Ivanov ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS);
757eadff302SIvan T. Ivanov if (ret < 0)
758eadff302SIvan T. Ivanov return ret;
759eadff302SIvan T. Ivanov
760eadff302SIvan T. Ivanov pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK;
761eadff302SIvan T. Ivanov }
762eadff302SIvan T. Ivanov
76386c1a219SLinus Walleij return !!pad->out_value;
764eadff302SIvan T. Ivanov }
765eadff302SIvan T. Ivanov
pmic_gpio_set(struct gpio_chip * chip,unsigned pin,int value)766eadff302SIvan T. Ivanov static void pmic_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
767eadff302SIvan T. Ivanov {
768c52d9df1SLinus Walleij struct pmic_gpio_state *state = gpiochip_get_data(chip);
769eadff302SIvan T. Ivanov unsigned long config;
770eadff302SIvan T. Ivanov
771eadff302SIvan T. Ivanov config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
772eadff302SIvan T. Ivanov
773eadff302SIvan T. Ivanov pmic_gpio_config_set(state->ctrl, pin, &config, 1);
774eadff302SIvan T. Ivanov }
775eadff302SIvan T. Ivanov
pmic_gpio_of_xlate(struct gpio_chip * chip,const struct of_phandle_args * gpio_desc,u32 * flags)776eadff302SIvan T. Ivanov static int pmic_gpio_of_xlate(struct gpio_chip *chip,
777eadff302SIvan T. Ivanov const struct of_phandle_args *gpio_desc,
778eadff302SIvan T. Ivanov u32 *flags)
779eadff302SIvan T. Ivanov {
780eadff302SIvan T. Ivanov if (chip->of_gpio_n_cells < 2)
781eadff302SIvan T. Ivanov return -EINVAL;
782eadff302SIvan T. Ivanov
783eadff302SIvan T. Ivanov if (flags)
784eadff302SIvan T. Ivanov *flags = gpio_desc->args[1];
785eadff302SIvan T. Ivanov
786eadff302SIvan T. Ivanov return gpio_desc->args[0] - PMIC_GPIO_PHYSICAL_OFFSET;
787eadff302SIvan T. Ivanov }
788eadff302SIvan T. Ivanov
pmic_gpio_dbg_show(struct seq_file * s,struct gpio_chip * chip)789eadff302SIvan T. Ivanov static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
790eadff302SIvan T. Ivanov {
791c52d9df1SLinus Walleij struct pmic_gpio_state *state = gpiochip_get_data(chip);
792eadff302SIvan T. Ivanov unsigned i;
793eadff302SIvan T. Ivanov
794eadff302SIvan T. Ivanov for (i = 0; i < chip->ngpio; i++) {
795eadff302SIvan T. Ivanov pmic_gpio_config_dbg_show(state->ctrl, s, i);
796eadff302SIvan T. Ivanov seq_puts(s, "\n");
797eadff302SIvan T. Ivanov }
798eadff302SIvan T. Ivanov }
799eadff302SIvan T. Ivanov
800eadff302SIvan T. Ivanov static const struct gpio_chip pmic_gpio_gpio_template = {
801eadff302SIvan T. Ivanov .direction_input = pmic_gpio_direction_input,
802eadff302SIvan T. Ivanov .direction_output = pmic_gpio_direction_output,
803eadff302SIvan T. Ivanov .get = pmic_gpio_get,
804eadff302SIvan T. Ivanov .set = pmic_gpio_set,
80598c85d58SJonas Gorski .request = gpiochip_generic_request,
80698c85d58SJonas Gorski .free = gpiochip_generic_free,
807eadff302SIvan T. Ivanov .of_xlate = pmic_gpio_of_xlate,
808eadff302SIvan T. Ivanov .dbg_show = pmic_gpio_dbg_show,
809eadff302SIvan T. Ivanov };
810eadff302SIvan T. Ivanov
pmic_gpio_populate(struct pmic_gpio_state * state,struct pmic_gpio_pad * pad)811eadff302SIvan T. Ivanov static int pmic_gpio_populate(struct pmic_gpio_state *state,
812eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad)
813eadff302SIvan T. Ivanov {
814eadff302SIvan T. Ivanov int type, subtype, val, dir;
815eadff302SIvan T. Ivanov
816eadff302SIvan T. Ivanov type = pmic_gpio_read(state, pad, PMIC_GPIO_REG_TYPE);
817eadff302SIvan T. Ivanov if (type < 0)
818eadff302SIvan T. Ivanov return type;
819eadff302SIvan T. Ivanov
820eadff302SIvan T. Ivanov if (type != PMIC_GPIO_TYPE) {
821eadff302SIvan T. Ivanov dev_err(state->dev, "incorrect block type 0x%x at 0x%x\n",
822eadff302SIvan T. Ivanov type, pad->base);
823eadff302SIvan T. Ivanov return -ENODEV;
824eadff302SIvan T. Ivanov }
825eadff302SIvan T. Ivanov
826eadff302SIvan T. Ivanov subtype = pmic_gpio_read(state, pad, PMIC_GPIO_REG_SUBTYPE);
827eadff302SIvan T. Ivanov if (subtype < 0)
828eadff302SIvan T. Ivanov return subtype;
829eadff302SIvan T. Ivanov
830eadff302SIvan T. Ivanov switch (subtype) {
831eadff302SIvan T. Ivanov case PMIC_GPIO_SUBTYPE_GPIO_4CH:
832eadff302SIvan T. Ivanov pad->have_buffer = true;
8331586f556SGustavo A. R. Silva fallthrough;
834eadff302SIvan T. Ivanov case PMIC_GPIO_SUBTYPE_GPIOC_4CH:
835eadff302SIvan T. Ivanov pad->num_sources = 4;
836eadff302SIvan T. Ivanov break;
837eadff302SIvan T. Ivanov case PMIC_GPIO_SUBTYPE_GPIO_8CH:
838eadff302SIvan T. Ivanov pad->have_buffer = true;
8391586f556SGustavo A. R. Silva fallthrough;
840eadff302SIvan T. Ivanov case PMIC_GPIO_SUBTYPE_GPIOC_8CH:
841eadff302SIvan T. Ivanov pad->num_sources = 8;
842eadff302SIvan T. Ivanov break;
843d7b5f5ccSFenglin Wu case PMIC_GPIO_SUBTYPE_GPIO_LV:
844d7b5f5ccSFenglin Wu pad->num_sources = 1;
845d7b5f5ccSFenglin Wu pad->have_buffer = true;
846d7b5f5ccSFenglin Wu pad->lv_mv_type = true;
847d7b5f5ccSFenglin Wu break;
848d7b5f5ccSFenglin Wu case PMIC_GPIO_SUBTYPE_GPIO_MV:
849d7b5f5ccSFenglin Wu pad->num_sources = 2;
850d7b5f5ccSFenglin Wu pad->have_buffer = true;
851d7b5f5ccSFenglin Wu pad->lv_mv_type = true;
852d7b5f5ccSFenglin Wu break;
8534af95d09SDavid Collins case PMIC_GPIO_SUBTYPE_GPIO_LV_VIN2:
8544af95d09SDavid Collins pad->num_sources = 2;
8554af95d09SDavid Collins pad->have_buffer = true;
8564af95d09SDavid Collins pad->lv_mv_type = true;
8574af95d09SDavid Collins break;
8584af95d09SDavid Collins case PMIC_GPIO_SUBTYPE_GPIO_MV_VIN3:
8594af95d09SDavid Collins pad->num_sources = 3;
8604af95d09SDavid Collins pad->have_buffer = true;
8614af95d09SDavid Collins pad->lv_mv_type = true;
8624af95d09SDavid Collins break;
863eadff302SIvan T. Ivanov default:
864eadff302SIvan T. Ivanov dev_err(state->dev, "unknown GPIO type 0x%x\n", subtype);
865eadff302SIvan T. Ivanov return -ENODEV;
866eadff302SIvan T. Ivanov }
867eadff302SIvan T. Ivanov
868d7b5f5ccSFenglin Wu if (pad->lv_mv_type) {
869d7b5f5ccSFenglin Wu val = pmic_gpio_read(state, pad,
870d7b5f5ccSFenglin Wu PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL);
871d7b5f5ccSFenglin Wu if (val < 0)
872d7b5f5ccSFenglin Wu return val;
873d7b5f5ccSFenglin Wu
874d7b5f5ccSFenglin Wu pad->out_value = !!(val & PMIC_GPIO_LV_MV_OUTPUT_INVERT);
875d7b5f5ccSFenglin Wu pad->function = val & PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK;
876d7b5f5ccSFenglin Wu
877d7b5f5ccSFenglin Wu val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL);
878d7b5f5ccSFenglin Wu if (val < 0)
879d7b5f5ccSFenglin Wu return val;
880d7b5f5ccSFenglin Wu
881d7b5f5ccSFenglin Wu dir = val & PMIC_GPIO_REG_LV_MV_MODE_DIR_MASK;
882d7b5f5ccSFenglin Wu } else {
883eadff302SIvan T. Ivanov val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL);
884eadff302SIvan T. Ivanov if (val < 0)
885eadff302SIvan T. Ivanov return val;
886eadff302SIvan T. Ivanov
887eadff302SIvan T. Ivanov pad->out_value = val & PMIC_GPIO_REG_MODE_VALUE_SHIFT;
888eadff302SIvan T. Ivanov
889eadff302SIvan T. Ivanov dir = val >> PMIC_GPIO_REG_MODE_DIR_SHIFT;
890eadff302SIvan T. Ivanov dir &= PMIC_GPIO_REG_MODE_DIR_MASK;
891d7b5f5ccSFenglin Wu pad->function = val >> PMIC_GPIO_REG_MODE_FUNCTION_SHIFT;
892d7b5f5ccSFenglin Wu pad->function &= PMIC_GPIO_REG_MODE_FUNCTION_MASK;
893d7b5f5ccSFenglin Wu }
894d7b5f5ccSFenglin Wu
895eadff302SIvan T. Ivanov switch (dir) {
896d7b5f5ccSFenglin Wu case PMIC_GPIO_MODE_DIGITAL_INPUT:
897eadff302SIvan T. Ivanov pad->input_enabled = true;
898eadff302SIvan T. Ivanov pad->output_enabled = false;
899eadff302SIvan T. Ivanov break;
900d7b5f5ccSFenglin Wu case PMIC_GPIO_MODE_DIGITAL_OUTPUT:
901eadff302SIvan T. Ivanov pad->input_enabled = false;
902eadff302SIvan T. Ivanov pad->output_enabled = true;
903eadff302SIvan T. Ivanov break;
904d7b5f5ccSFenglin Wu case PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT:
905eadff302SIvan T. Ivanov pad->input_enabled = true;
906eadff302SIvan T. Ivanov pad->output_enabled = true;
907eadff302SIvan T. Ivanov break;
908d7b5f5ccSFenglin Wu case PMIC_GPIO_MODE_ANALOG_PASS_THRU:
909d7b5f5ccSFenglin Wu if (!pad->lv_mv_type)
910d7b5f5ccSFenglin Wu return -ENODEV;
911d7b5f5ccSFenglin Wu pad->analog_pass = true;
912d7b5f5ccSFenglin Wu break;
913eadff302SIvan T. Ivanov default:
914eadff302SIvan T. Ivanov dev_err(state->dev, "unknown GPIO direction\n");
915eadff302SIvan T. Ivanov return -ENODEV;
916eadff302SIvan T. Ivanov }
917eadff302SIvan T. Ivanov
918eadff302SIvan T. Ivanov val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL);
919eadff302SIvan T. Ivanov if (val < 0)
920eadff302SIvan T. Ivanov return val;
921eadff302SIvan T. Ivanov
922eadff302SIvan T. Ivanov pad->power_source = val >> PMIC_GPIO_REG_VIN_SHIFT;
923eadff302SIvan T. Ivanov pad->power_source &= PMIC_GPIO_REG_VIN_MASK;
924eadff302SIvan T. Ivanov
925eadff302SIvan T. Ivanov val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_PULL_CTL);
926eadff302SIvan T. Ivanov if (val < 0)
927eadff302SIvan T. Ivanov return val;
928eadff302SIvan T. Ivanov
929eadff302SIvan T. Ivanov pad->pullup = val >> PMIC_GPIO_REG_PULL_SHIFT;
930eadff302SIvan T. Ivanov pad->pullup &= PMIC_GPIO_REG_PULL_MASK;
931eadff302SIvan T. Ivanov
932223463fcSFenglin Wu val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_IN_CTL);
933223463fcSFenglin Wu if (val < 0)
934223463fcSFenglin Wu return val;
935223463fcSFenglin Wu
936223463fcSFenglin Wu if (pad->lv_mv_type && (val & PMIC_GPIO_LV_MV_DIG_IN_DTEST_EN))
937223463fcSFenglin Wu pad->dtest_buffer =
938223463fcSFenglin Wu (val & PMIC_GPIO_LV_MV_DIG_IN_DTEST_SEL_MASK) + 1;
939223463fcSFenglin Wu else if (!pad->lv_mv_type)
940223463fcSFenglin Wu pad->dtest_buffer = ffs(val);
941223463fcSFenglin Wu else
942223463fcSFenglin Wu pad->dtest_buffer = 0;
943223463fcSFenglin Wu
944223463fcSFenglin Wu val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL);
945223463fcSFenglin Wu if (val < 0)
946223463fcSFenglin Wu return val;
947223463fcSFenglin Wu
948eadff302SIvan T. Ivanov pad->strength = val >> PMIC_GPIO_REG_OUT_STRENGTH_SHIFT;
949eadff302SIvan T. Ivanov pad->strength &= PMIC_GPIO_REG_OUT_STRENGTH_MASK;
950eadff302SIvan T. Ivanov
951eadff302SIvan T. Ivanov pad->buffer_type = val >> PMIC_GPIO_REG_OUT_TYPE_SHIFT;
952eadff302SIvan T. Ivanov pad->buffer_type &= PMIC_GPIO_REG_OUT_TYPE_MASK;
953eadff302SIvan T. Ivanov
954d7b5f5ccSFenglin Wu if (pad->lv_mv_type) {
955d7b5f5ccSFenglin Wu val = pmic_gpio_read(state, pad,
956d7b5f5ccSFenglin Wu PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL);
957d7b5f5ccSFenglin Wu if (val < 0)
958d7b5f5ccSFenglin Wu return val;
959d7b5f5ccSFenglin Wu pad->atest = (val & PMIC_GPIO_LV_MV_ANA_MUX_SEL_MASK) + 1;
960d7b5f5ccSFenglin Wu }
961d7b5f5ccSFenglin Wu
962eadff302SIvan T. Ivanov /* Pin could be disabled with PIN_CONFIG_BIAS_HIGH_IMPEDANCE */
963eadff302SIvan T. Ivanov pad->is_enabled = true;
964eadff302SIvan T. Ivanov return 0;
965eadff302SIvan T. Ivanov }
966eadff302SIvan T. Ivanov
pmic_gpio_domain_translate(struct irq_domain * domain,struct irq_fwspec * fwspec,unsigned long * hwirq,unsigned int * type)967ca69e2d1SBrian Masney static int pmic_gpio_domain_translate(struct irq_domain *domain,
968ca69e2d1SBrian Masney struct irq_fwspec *fwspec,
969ca69e2d1SBrian Masney unsigned long *hwirq,
970ca69e2d1SBrian Masney unsigned int *type)
971ca69e2d1SBrian Masney {
972ca69e2d1SBrian Masney struct pmic_gpio_state *state = container_of(domain->host_data,
973ca69e2d1SBrian Masney struct pmic_gpio_state,
974ca69e2d1SBrian Masney chip);
975ca69e2d1SBrian Masney
976dac7da98SBjorn Andersson if (fwspec->param_count != 2 ||
977dac7da98SBjorn Andersson fwspec->param[0] < 1 || fwspec->param[0] > state->chip.ngpio)
978ca69e2d1SBrian Masney return -EINVAL;
979ca69e2d1SBrian Masney
980ca69e2d1SBrian Masney *hwirq = fwspec->param[0] - PMIC_GPIO_PHYSICAL_OFFSET;
981ca69e2d1SBrian Masney *type = fwspec->param[1];
982ca69e2d1SBrian Masney
983ca69e2d1SBrian Masney return 0;
984ca69e2d1SBrian Masney }
985ca69e2d1SBrian Masney
pmic_gpio_child_offset_to_irq(struct gpio_chip * chip,unsigned int offset)986821c76c4SBrian Masney static unsigned int pmic_gpio_child_offset_to_irq(struct gpio_chip *chip,
987821c76c4SBrian Masney unsigned int offset)
988ca69e2d1SBrian Masney {
989821c76c4SBrian Masney return offset + PMIC_GPIO_PHYSICAL_OFFSET;
990ca69e2d1SBrian Masney }
991ca69e2d1SBrian Masney
pmic_gpio_child_to_parent_hwirq(struct gpio_chip * chip,unsigned int child_hwirq,unsigned int child_type,unsigned int * parent_hwirq,unsigned int * parent_type)992821c76c4SBrian Masney static int pmic_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
993821c76c4SBrian Masney unsigned int child_hwirq,
994821c76c4SBrian Masney unsigned int child_type,
995821c76c4SBrian Masney unsigned int *parent_hwirq,
996821c76c4SBrian Masney unsigned int *parent_type)
997821c76c4SBrian Masney {
998d36a9773SDavid Collins struct pmic_gpio_state *state = gpiochip_get_data(chip);
999d36a9773SDavid Collins
1000d36a9773SDavid Collins *parent_hwirq = child_hwirq + state->pid_base;
1001821c76c4SBrian Masney *parent_type = child_type;
1002821c76c4SBrian Masney
1003821c76c4SBrian Masney return 0;
1004821c76c4SBrian Masney }
1005ca69e2d1SBrian Masney
pmic_gpio_populate_parent_fwspec(struct gpio_chip * chip,union gpio_irq_fwspec * gfwspec,unsigned int parent_hwirq,unsigned int parent_type)100691a29af4SMarc Zyngier static int pmic_gpio_populate_parent_fwspec(struct gpio_chip *chip,
100791a29af4SMarc Zyngier union gpio_irq_fwspec *gfwspec,
1008d36a9773SDavid Collins unsigned int parent_hwirq,
1009d36a9773SDavid Collins unsigned int parent_type)
1010d36a9773SDavid Collins {
1011d36a9773SDavid Collins struct pmic_gpio_state *state = gpiochip_get_data(chip);
101291a29af4SMarc Zyngier struct irq_fwspec *fwspec = &gfwspec->fwspec;
1013d36a9773SDavid Collins
1014d36a9773SDavid Collins fwspec->fwnode = chip->irq.parent_domain->fwnode;
1015d36a9773SDavid Collins
1016d36a9773SDavid Collins fwspec->param_count = 4;
1017d36a9773SDavid Collins fwspec->param[0] = state->usid;
1018d36a9773SDavid Collins fwspec->param[1] = parent_hwirq;
1019d36a9773SDavid Collins /* param[2] must be left as 0 */
1020d36a9773SDavid Collins fwspec->param[3] = parent_type;
1021d36a9773SDavid Collins
102291a29af4SMarc Zyngier return 0;
1023d36a9773SDavid Collins }
1024d36a9773SDavid Collins
pmic_gpio_irq_mask(struct irq_data * data)10251a41d1e5SManivannan Sadhasivam static void pmic_gpio_irq_mask(struct irq_data *data)
10261a41d1e5SManivannan Sadhasivam {
10271a41d1e5SManivannan Sadhasivam struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
10281a41d1e5SManivannan Sadhasivam
10291a41d1e5SManivannan Sadhasivam irq_chip_mask_parent(data);
10301a41d1e5SManivannan Sadhasivam gpiochip_disable_irq(gc, data->hwirq);
10311a41d1e5SManivannan Sadhasivam }
10321a41d1e5SManivannan Sadhasivam
pmic_gpio_irq_unmask(struct irq_data * data)10331a41d1e5SManivannan Sadhasivam static void pmic_gpio_irq_unmask(struct irq_data *data)
10341a41d1e5SManivannan Sadhasivam {
10351a41d1e5SManivannan Sadhasivam struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
10361a41d1e5SManivannan Sadhasivam
10371a41d1e5SManivannan Sadhasivam gpiochip_enable_irq(gc, data->hwirq);
10381a41d1e5SManivannan Sadhasivam irq_chip_unmask_parent(data);
10391a41d1e5SManivannan Sadhasivam }
10401a41d1e5SManivannan Sadhasivam
10411a41d1e5SManivannan Sadhasivam static const struct irq_chip spmi_gpio_irq_chip = {
10421a41d1e5SManivannan Sadhasivam .name = "spmi-gpio",
10431a41d1e5SManivannan Sadhasivam .irq_ack = irq_chip_ack_parent,
10441a41d1e5SManivannan Sadhasivam .irq_mask = pmic_gpio_irq_mask,
10451a41d1e5SManivannan Sadhasivam .irq_unmask = pmic_gpio_irq_unmask,
10461a41d1e5SManivannan Sadhasivam .irq_set_type = irq_chip_set_type_parent,
10471a41d1e5SManivannan Sadhasivam .irq_set_wake = irq_chip_set_wake_parent,
10481a41d1e5SManivannan Sadhasivam .flags = IRQCHIP_IMMUTABLE | IRQCHIP_MASK_ON_SUSPEND,
10491a41d1e5SManivannan Sadhasivam GPIOCHIP_IRQ_RESOURCE_HELPERS,
10501a41d1e5SManivannan Sadhasivam };
10511a41d1e5SManivannan Sadhasivam
pmic_gpio_probe(struct platform_device * pdev)1052eadff302SIvan T. Ivanov static int pmic_gpio_probe(struct platform_device *pdev)
1053eadff302SIvan T. Ivanov {
1054ca69e2d1SBrian Masney struct irq_domain *parent_domain;
1055ca69e2d1SBrian Masney struct device_node *parent_node;
1056eadff302SIvan T. Ivanov struct device *dev = &pdev->dev;
1057eadff302SIvan T. Ivanov struct pinctrl_pin_desc *pindesc;
1058eadff302SIvan T. Ivanov struct pinctrl_desc *pctrldesc;
1059eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad, *pads;
1060eadff302SIvan T. Ivanov struct pmic_gpio_state *state;
1061821c76c4SBrian Masney struct gpio_irq_chip *girq;
1062d36a9773SDavid Collins const struct spmi_device *parent_spmi_dev;
1063eadff302SIvan T. Ivanov int ret, npins, i;
1064ab4256cfSStephen Boyd u32 reg;
1065eadff302SIvan T. Ivanov
1066ab4256cfSStephen Boyd ret = of_property_read_u32(dev->of_node, "reg", ®);
1067eadff302SIvan T. Ivanov if (ret < 0) {
1068ab4256cfSStephen Boyd dev_err(dev, "missing base address");
1069eadff302SIvan T. Ivanov return ret;
1070eadff302SIvan T. Ivanov }
1071eadff302SIvan T. Ivanov
1072cfacef37SBrian Masney npins = (uintptr_t) device_get_match_data(&pdev->dev);
1073eadff302SIvan T. Ivanov
1074eadff302SIvan T. Ivanov state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
1075eadff302SIvan T. Ivanov if (!state)
1076eadff302SIvan T. Ivanov return -ENOMEM;
1077eadff302SIvan T. Ivanov
1078eadff302SIvan T. Ivanov platform_set_drvdata(pdev, state);
1079eadff302SIvan T. Ivanov
1080eadff302SIvan T. Ivanov state->dev = &pdev->dev;
1081eadff302SIvan T. Ivanov state->map = dev_get_regmap(dev->parent, NULL);
1082d36a9773SDavid Collins parent_spmi_dev = to_spmi_device(dev->parent);
1083d36a9773SDavid Collins state->usid = parent_spmi_dev->usid;
1084d36a9773SDavid Collins state->pid_base = reg >> 8;
1085eadff302SIvan T. Ivanov
1086eadff302SIvan T. Ivanov pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
1087eadff302SIvan T. Ivanov if (!pindesc)
1088eadff302SIvan T. Ivanov return -ENOMEM;
1089eadff302SIvan T. Ivanov
1090eadff302SIvan T. Ivanov pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL);
1091eadff302SIvan T. Ivanov if (!pads)
1092eadff302SIvan T. Ivanov return -ENOMEM;
1093eadff302SIvan T. Ivanov
1094eadff302SIvan T. Ivanov pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL);
1095eadff302SIvan T. Ivanov if (!pctrldesc)
1096eadff302SIvan T. Ivanov return -ENOMEM;
1097eadff302SIvan T. Ivanov
1098eadff302SIvan T. Ivanov pctrldesc->pctlops = &pmic_gpio_pinctrl_ops;
1099eadff302SIvan T. Ivanov pctrldesc->pmxops = &pmic_gpio_pinmux_ops;
1100eadff302SIvan T. Ivanov pctrldesc->confops = &pmic_gpio_pinconf_ops;
1101eadff302SIvan T. Ivanov pctrldesc->owner = THIS_MODULE;
1102eadff302SIvan T. Ivanov pctrldesc->name = dev_name(dev);
1103eadff302SIvan T. Ivanov pctrldesc->pins = pindesc;
1104eadff302SIvan T. Ivanov pctrldesc->npins = npins;
1105f684e4acSLinus Walleij pctrldesc->num_custom_params = ARRAY_SIZE(pmic_gpio_bindings);
1106f684e4acSLinus Walleij pctrldesc->custom_params = pmic_gpio_bindings;
11074f06266aSArnd Bergmann #ifdef CONFIG_DEBUG_FS
1108f684e4acSLinus Walleij pctrldesc->custom_conf_items = pmic_conf_items;
11094f06266aSArnd Bergmann #endif
1110eadff302SIvan T. Ivanov
1111eadff302SIvan T. Ivanov for (i = 0; i < npins; i++, pindesc++) {
1112eadff302SIvan T. Ivanov pad = &pads[i];
1113eadff302SIvan T. Ivanov pindesc->drv_data = pad;
1114eadff302SIvan T. Ivanov pindesc->number = i;
1115eadff302SIvan T. Ivanov pindesc->name = pmic_gpio_groups[i];
1116eadff302SIvan T. Ivanov
1117ab4256cfSStephen Boyd pad->base = reg + i * PMIC_GPIO_ADDRESS_RANGE;
1118eadff302SIvan T. Ivanov
1119eadff302SIvan T. Ivanov ret = pmic_gpio_populate(state, pad);
1120eadff302SIvan T. Ivanov if (ret < 0)
1121eadff302SIvan T. Ivanov return ret;
1122eadff302SIvan T. Ivanov }
1123eadff302SIvan T. Ivanov
1124eadff302SIvan T. Ivanov state->chip = pmic_gpio_gpio_template;
112558383c78SLinus Walleij state->chip.parent = dev;
1126eadff302SIvan T. Ivanov state->chip.base = -1;
1127eadff302SIvan T. Ivanov state->chip.ngpio = npins;
1128eadff302SIvan T. Ivanov state->chip.label = dev_name(dev);
1129eadff302SIvan T. Ivanov state->chip.of_gpio_n_cells = 2;
1130eadff302SIvan T. Ivanov state->chip.can_sleep = false;
1131eadff302SIvan T. Ivanov
1132b46ddfe6SLaxman Dewangan state->ctrl = devm_pinctrl_register(dev, pctrldesc, state);
1133323de9efSMasahiro Yamada if (IS_ERR(state->ctrl))
1134323de9efSMasahiro Yamada return PTR_ERR(state->ctrl);
1135eadff302SIvan T. Ivanov
1136ca69e2d1SBrian Masney parent_node = of_irq_find_parent(state->dev->of_node);
1137ca69e2d1SBrian Masney if (!parent_node)
1138ca69e2d1SBrian Masney return -ENXIO;
1139ca69e2d1SBrian Masney
1140ca69e2d1SBrian Masney parent_domain = irq_find_host(parent_node);
1141ca69e2d1SBrian Masney of_node_put(parent_node);
1142ca69e2d1SBrian Masney if (!parent_domain)
1143ca69e2d1SBrian Masney return -ENXIO;
1144ca69e2d1SBrian Masney
1145821c76c4SBrian Masney girq = &state->chip.irq;
11461a41d1e5SManivannan Sadhasivam gpio_irq_chip_set_chip(girq, &spmi_gpio_irq_chip);
1147821c76c4SBrian Masney girq->default_type = IRQ_TYPE_NONE;
1148821c76c4SBrian Masney girq->handler = handle_level_irq;
11499bd73ce0SAndy Shevchenko girq->fwnode = dev_fwnode(state->dev);
1150821c76c4SBrian Masney girq->parent_domain = parent_domain;
1151821c76c4SBrian Masney girq->child_to_parent_hwirq = pmic_gpio_child_to_parent_hwirq;
1152d36a9773SDavid Collins girq->populate_parent_alloc_arg = pmic_gpio_populate_parent_fwspec;
1153821c76c4SBrian Masney girq->child_offset_to_irq = pmic_gpio_child_offset_to_irq;
1154821c76c4SBrian Masney girq->child_irq_domain_ops.translate = pmic_gpio_domain_translate;
1155ca69e2d1SBrian Masney
1156c52d9df1SLinus Walleij ret = gpiochip_add_data(&state->chip, state);
1157eadff302SIvan T. Ivanov if (ret) {
1158eadff302SIvan T. Ivanov dev_err(state->dev, "can't add gpio chip\n");
1159821c76c4SBrian Masney return ret;
1160eadff302SIvan T. Ivanov }
1161eadff302SIvan T. Ivanov
1162149a9604SBrian Masney /*
1163149a9604SBrian Masney * For DeviceTree-supported systems, the gpio core checks the
1164149a9604SBrian Masney * pinctrl's device node for the "gpio-ranges" property.
1165149a9604SBrian Masney * If it is present, it takes care of adding the pin ranges
1166149a9604SBrian Masney * for the driver. In this case the driver can skip ahead.
1167149a9604SBrian Masney *
1168149a9604SBrian Masney * In order to remain compatible with older, existing DeviceTree
1169149a9604SBrian Masney * files which don't set the "gpio-ranges" property or systems that
1170149a9604SBrian Masney * utilize ACPI the driver has to call gpiochip_add_pin_range().
1171149a9604SBrian Masney */
1172149a9604SBrian Masney if (!of_property_read_bool(dev->of_node, "gpio-ranges")) {
1173149a9604SBrian Masney ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0,
1174149a9604SBrian Masney npins);
1175eadff302SIvan T. Ivanov if (ret) {
1176eadff302SIvan T. Ivanov dev_err(dev, "failed to add pin range\n");
1177eadff302SIvan T. Ivanov goto err_range;
1178eadff302SIvan T. Ivanov }
1179149a9604SBrian Masney }
1180eadff302SIvan T. Ivanov
1181eadff302SIvan T. Ivanov return 0;
1182eadff302SIvan T. Ivanov
1183eadff302SIvan T. Ivanov err_range:
1184eadff302SIvan T. Ivanov gpiochip_remove(&state->chip);
1185eadff302SIvan T. Ivanov return ret;
1186eadff302SIvan T. Ivanov }
1187eadff302SIvan T. Ivanov
pmic_gpio_remove(struct platform_device * pdev)1188eadff302SIvan T. Ivanov static int pmic_gpio_remove(struct platform_device *pdev)
1189eadff302SIvan T. Ivanov {
1190eadff302SIvan T. Ivanov struct pmic_gpio_state *state = platform_get_drvdata(pdev);
1191eadff302SIvan T. Ivanov
1192eadff302SIvan T. Ivanov gpiochip_remove(&state->chip);
1193eadff302SIvan T. Ivanov return 0;
1194eadff302SIvan T. Ivanov }
1195eadff302SIvan T. Ivanov
1196eadff302SIvan T. Ivanov static const struct of_device_id pmic_gpio_of_match[] = {
1197ef874e03SLoic Poulain { .compatible = "qcom,pm2250-gpio", .data = (void *) 10 },
119817cc38e7SKonrad Dybcio /* pm660 has 13 GPIOs with holes on 1, 5, 6, 7, 8 and 10 */
119917cc38e7SKonrad Dybcio { .compatible = "qcom,pm660-gpio", .data = (void *) 13 },
120017cc38e7SKonrad Dybcio /* pm660l has 12 GPIOs with holes on 1, 2, 10, 11 and 12 */
120117cc38e7SKonrad Dybcio { .compatible = "qcom,pm660l-gpio", .data = (void *) 12 },
12024d8a768eSMarijn Suijten { .compatible = "qcom,pm6125-gpio", .data = (void *) 9 },
12034afc2a0cSBhupesh Sharma { .compatible = "qcom,pm6150-gpio", .data = (void *) 10 },
12044afc2a0cSBhupesh Sharma { .compatible = "qcom,pm6150l-gpio", .data = (void *) 12 },
120583917856SLuca Weiss { .compatible = "qcom,pm6350-gpio", .data = (void *) 9 },
12063d46ff83SJishnu Prakash { .compatible = "qcom,pm7250b-gpio", .data = (void *) 12 },
12074afc2a0cSBhupesh Sharma { .compatible = "qcom,pm7325-gpio", .data = (void *) 10 },
12088fff6514SRohit Agarwal { .compatible = "qcom,pm7550ba-gpio", .data = (void *) 8},
12094afc2a0cSBhupesh Sharma { .compatible = "qcom,pm8005-gpio", .data = (void *) 4 },
12104afc2a0cSBhupesh Sharma { .compatible = "qcom,pm8008-gpio", .data = (void *) 2 },
1211f3474383SKonrad Dybcio { .compatible = "qcom,pm8019-gpio", .data = (void *) 6 },
1212d67070c3SVinod Koul /* pm8150 has 10 GPIOs with holes on 2, 5, 7 and 8 */
1213d67070c3SVinod Koul { .compatible = "qcom,pm8150-gpio", .data = (void *) 10 },
1214182700f2SBjorn Andersson { .compatible = "qcom,pmc8180-gpio", .data = (void *) 10 },
12159bdacaddSVinod Koul /* pm8150b has 12 GPIOs with holes on 3, r and 7 */
12169bdacaddSVinod Koul { .compatible = "qcom,pm8150b-gpio", .data = (void *) 12 },
12172dc889a8SVinod Koul /* pm8150l has 12 GPIOs with holes on 7 */
12182dc889a8SVinod Koul { .compatible = "qcom,pm8150l-gpio", .data = (void *) 12 },
1219182700f2SBjorn Andersson { .compatible = "qcom,pmc8180c-gpio", .data = (void *) 12 },
1220eebe11b5SDominik Kobinski { .compatible = "qcom,pm8226-gpio", .data = (void *) 8 },
122157c0a4f0SVinod Koul { .compatible = "qcom,pm8350-gpio", .data = (void *) 10 },
122257c0a4f0SVinod Koul { .compatible = "qcom,pm8350b-gpio", .data = (void *) 8 },
122357c0a4f0SVinod Koul { .compatible = "qcom,pm8350c-gpio", .data = (void *) 9 },
1224168a0abfSDmitry Baryshkov { .compatible = "qcom,pm8450-gpio", .data = (void *) 4 },
1225e8c39b3eSNeil Armstrong { .compatible = "qcom,pm8550-gpio", .data = (void *) 12 },
1226e8c39b3eSNeil Armstrong { .compatible = "qcom,pm8550b-gpio", .data = (void *) 12 },
1227e8c39b3eSNeil Armstrong { .compatible = "qcom,pm8550ve-gpio", .data = (void *) 8 },
1228e8c39b3eSNeil Armstrong { .compatible = "qcom,pm8550vs-gpio", .data = (void *) 6 },
12294afc2a0cSBhupesh Sharma { .compatible = "qcom,pm8916-gpio", .data = (void *) 4 },
12304afc2a0cSBhupesh Sharma { .compatible = "qcom,pm8941-gpio", .data = (void *) 36 },
12314afc2a0cSBhupesh Sharma /* pm8950 has 8 GPIOs with holes on 3 */
12324afc2a0cSBhupesh Sharma { .compatible = "qcom,pm8950-gpio", .data = (void *) 8 },
1233cbbe0778SLuca Weiss /* pm8953 has 8 GPIOs with holes on 3 and 6 */
1234cbbe0778SLuca Weiss { .compatible = "qcom,pm8953-gpio", .data = (void *) 8 },
12354afc2a0cSBhupesh Sharma { .compatible = "qcom,pm8994-gpio", .data = (void *) 22 },
12364afc2a0cSBhupesh Sharma { .compatible = "qcom,pm8998-gpio", .data = (void *) 26 },
12374afc2a0cSBhupesh Sharma { .compatible = "qcom,pma8084-gpio", .data = (void *) 22 },
12387abf7f88SLuca Weiss { .compatible = "qcom,pmi632-gpio", .data = (void *) 8 },
12394afc2a0cSBhupesh Sharma { .compatible = "qcom,pmi8950-gpio", .data = (void *) 2 },
12404afc2a0cSBhupesh Sharma { .compatible = "qcom,pmi8994-gpio", .data = (void *) 10 },
12414afc2a0cSBhupesh Sharma { .compatible = "qcom,pmi8998-gpio", .data = (void *) 14 },
124257c0a4f0SVinod Koul { .compatible = "qcom,pmk8350-gpio", .data = (void *) 4 },
1243e8c39b3eSNeil Armstrong { .compatible = "qcom,pmk8550-gpio", .data = (void *) 6 },
124479e2311cSBhupesh Sharma { .compatible = "qcom,pmm8155au-gpio", .data = (void *) 10 },
12450538897aSBartosz Golaszewski { .compatible = "qcom,pmm8654au-gpio", .data = (void *) 12 },
12466cd81a86SRobert Marko /* pmp8074 has 12 GPIOs with holes on 1 and 12 */
12476cd81a86SRobert Marko { .compatible = "qcom,pmp8074-gpio", .data = (void *) 12 },
124857c0a4f0SVinod Koul { .compatible = "qcom,pmr735a-gpio", .data = (void *) 4 },
124957c0a4f0SVinod Koul { .compatible = "qcom,pmr735b-gpio", .data = (void *) 4 },
1250e8c39b3eSNeil Armstrong { .compatible = "qcom,pmr735d-gpio", .data = (void *) 2 },
12514afc2a0cSBhupesh Sharma /* pms405 has 12 GPIOs with holes on 1, 9, and 10 */
12524afc2a0cSBhupesh Sharma { .compatible = "qcom,pms405-gpio", .data = (void *) 12 },
1253ceb58de4SVinod Koul /* pmx55 has 11 GPIOs with holes on 3, 7, 10, 11 */
1254ceb58de4SVinod Koul { .compatible = "qcom,pmx55-gpio", .data = (void *) 11 },
1255203638fdSRohit Agarwal { .compatible = "qcom,pmx65-gpio", .data = (void *) 16 },
1256*1e46c743SRohit Agarwal { .compatible = "qcom,pmx75-gpio", .data = (void *) 16 },
1257eadff302SIvan T. Ivanov { },
1258eadff302SIvan T. Ivanov };
1259eadff302SIvan T. Ivanov
1260eadff302SIvan T. Ivanov MODULE_DEVICE_TABLE(of, pmic_gpio_of_match);
1261eadff302SIvan T. Ivanov
1262eadff302SIvan T. Ivanov static struct platform_driver pmic_gpio_driver = {
1263eadff302SIvan T. Ivanov .driver = {
1264eadff302SIvan T. Ivanov .name = "qcom-spmi-gpio",
1265eadff302SIvan T. Ivanov .of_match_table = pmic_gpio_of_match,
1266eadff302SIvan T. Ivanov },
1267eadff302SIvan T. Ivanov .probe = pmic_gpio_probe,
1268eadff302SIvan T. Ivanov .remove = pmic_gpio_remove,
1269eadff302SIvan T. Ivanov };
1270eadff302SIvan T. Ivanov
1271eadff302SIvan T. Ivanov module_platform_driver(pmic_gpio_driver);
1272eadff302SIvan T. Ivanov
1273eadff302SIvan T. Ivanov MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
1274eadff302SIvan T. Ivanov MODULE_DESCRIPTION("Qualcomm SPMI PMIC GPIO pin control driver");
1275eadff302SIvan T. Ivanov MODULE_ALIAS("platform:qcom-spmi-gpio");
1276eadff302SIvan T. Ivanov MODULE_LICENSE("GPL v2");
1277