1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Dialog DA9062 pinctrl and GPIO driver. |
4 | * Based on DA9055 GPIO driver. |
5 | * |
6 | * TODO: |
7 | * - add pinmux and pinctrl support (gpio alternate mode) |
8 | * |
9 | * Documents: |
10 | * [1] https://www.dialog-semiconductor.com/sites/default/files/da9062_datasheet_3v6.pdf |
11 | * |
12 | * Copyright (C) 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de> |
13 | */ |
14 | #include <linux/bits.h> |
15 | #include <linux/module.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/property.h> |
18 | #include <linux/regmap.h> |
19 | |
20 | #include <linux/gpio/consumer.h> |
21 | #include <linux/gpio/driver.h> |
22 | |
23 | #include <linux/mfd/da9062/core.h> |
24 | #include <linux/mfd/da9062/registers.h> |
25 | |
26 | #define DA9062_TYPE(offset) (4 * (offset % 2)) |
27 | #define DA9062_PIN_SHIFT(offset) (4 * (offset % 2)) |
28 | #define DA9062_PIN_ALTERNATE 0x00 /* gpio alternate mode */ |
29 | #define DA9062_PIN_GPI 0x01 /* gpio in */ |
30 | #define DA9062_PIN_GPO_OD 0x02 /* gpio out open-drain */ |
31 | #define DA9062_PIN_GPO_PP 0x03 /* gpio out push-pull */ |
32 | #define DA9062_GPIO_NUM 5 |
33 | |
34 | struct da9062_pctl { |
35 | struct da9062 *da9062; |
36 | struct gpio_chip gc; |
37 | unsigned int pin_config[DA9062_GPIO_NUM]; |
38 | }; |
39 | |
40 | static int da9062_pctl_get_pin_mode(struct da9062_pctl *pctl, |
41 | unsigned int offset) |
42 | { |
43 | struct regmap *regmap = pctl->da9062->regmap; |
44 | int ret, val; |
45 | |
46 | ret = regmap_read(map: regmap, DA9062AA_GPIO_0_1 + (offset >> 1), val: &val); |
47 | if (ret < 0) |
48 | return ret; |
49 | |
50 | val >>= DA9062_PIN_SHIFT(offset); |
51 | val &= DA9062AA_GPIO0_PIN_MASK; |
52 | |
53 | return val; |
54 | } |
55 | |
56 | static int da9062_pctl_set_pin_mode(struct da9062_pctl *pctl, |
57 | unsigned int offset, unsigned int mode_req) |
58 | { |
59 | struct regmap *regmap = pctl->da9062->regmap; |
60 | unsigned int mode = mode_req; |
61 | unsigned int mask; |
62 | int ret; |
63 | |
64 | mode &= DA9062AA_GPIO0_PIN_MASK; |
65 | mode <<= DA9062_PIN_SHIFT(offset); |
66 | mask = DA9062AA_GPIO0_PIN_MASK << DA9062_PIN_SHIFT(offset); |
67 | |
68 | ret = regmap_update_bits(map: regmap, DA9062AA_GPIO_0_1 + (offset >> 1), |
69 | mask, val: mode); |
70 | if (!ret) |
71 | pctl->pin_config[offset] = mode_req; |
72 | |
73 | return ret; |
74 | } |
75 | |
76 | static int da9062_gpio_get(struct gpio_chip *gc, unsigned int offset) |
77 | { |
78 | struct da9062_pctl *pctl = gpiochip_get_data(gc); |
79 | struct regmap *regmap = pctl->da9062->regmap; |
80 | int gpio_mode, val; |
81 | int ret; |
82 | |
83 | gpio_mode = da9062_pctl_get_pin_mode(pctl, offset); |
84 | if (gpio_mode < 0) |
85 | return gpio_mode; |
86 | |
87 | switch (gpio_mode) { |
88 | case DA9062_PIN_ALTERNATE: |
89 | return -ENOTSUPP; |
90 | case DA9062_PIN_GPI: |
91 | ret = regmap_read(map: regmap, DA9062AA_STATUS_B, val: &val); |
92 | if (ret < 0) |
93 | return ret; |
94 | break; |
95 | case DA9062_PIN_GPO_OD: |
96 | case DA9062_PIN_GPO_PP: |
97 | ret = regmap_read(map: regmap, DA9062AA_GPIO_MODE0_4, val: &val); |
98 | if (ret < 0) |
99 | return ret; |
100 | } |
101 | |
102 | return !!(val & BIT(offset)); |
103 | } |
104 | |
105 | static void da9062_gpio_set(struct gpio_chip *gc, unsigned int offset, |
106 | int value) |
107 | { |
108 | struct da9062_pctl *pctl = gpiochip_get_data(gc); |
109 | struct regmap *regmap = pctl->da9062->regmap; |
110 | |
111 | regmap_update_bits(map: regmap, DA9062AA_GPIO_MODE0_4, BIT(offset), |
112 | val: value << offset); |
113 | } |
114 | |
115 | static int da9062_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) |
116 | { |
117 | struct da9062_pctl *pctl = gpiochip_get_data(gc); |
118 | int gpio_mode; |
119 | |
120 | gpio_mode = da9062_pctl_get_pin_mode(pctl, offset); |
121 | if (gpio_mode < 0) |
122 | return gpio_mode; |
123 | |
124 | switch (gpio_mode) { |
125 | case DA9062_PIN_ALTERNATE: |
126 | return -ENOTSUPP; |
127 | case DA9062_PIN_GPI: |
128 | return GPIO_LINE_DIRECTION_IN; |
129 | case DA9062_PIN_GPO_OD: |
130 | case DA9062_PIN_GPO_PP: |
131 | return GPIO_LINE_DIRECTION_OUT; |
132 | } |
133 | |
134 | return -EINVAL; |
135 | } |
136 | |
137 | static int da9062_gpio_direction_input(struct gpio_chip *gc, |
138 | unsigned int offset) |
139 | { |
140 | struct da9062_pctl *pctl = gpiochip_get_data(gc); |
141 | struct regmap *regmap = pctl->da9062->regmap; |
142 | struct gpio_desc *desc = gpiochip_get_desc(gc, hwnum: offset); |
143 | unsigned int gpi_type; |
144 | int ret; |
145 | |
146 | ret = da9062_pctl_set_pin_mode(pctl, offset, DA9062_PIN_GPI); |
147 | if (ret) |
148 | return ret; |
149 | |
150 | /* |
151 | * If the gpio is active low we should set it in hw too. No worries |
152 | * about gpio_get() because we read and return the gpio-level. So the |
153 | * gpiolib active_low handling is still correct. |
154 | * |
155 | * 0 - active low, 1 - active high |
156 | */ |
157 | gpi_type = !gpiod_is_active_low(desc); |
158 | |
159 | return regmap_update_bits(map: regmap, DA9062AA_GPIO_0_1 + (offset >> 1), |
160 | DA9062AA_GPIO0_TYPE_MASK << DA9062_TYPE(offset), |
161 | val: gpi_type << DA9062_TYPE(offset)); |
162 | } |
163 | |
164 | static int da9062_gpio_direction_output(struct gpio_chip *gc, |
165 | unsigned int offset, int value) |
166 | { |
167 | struct da9062_pctl *pctl = gpiochip_get_data(gc); |
168 | unsigned int pin_config = pctl->pin_config[offset]; |
169 | int ret; |
170 | |
171 | ret = da9062_pctl_set_pin_mode(pctl, offset, mode_req: pin_config); |
172 | if (ret) |
173 | return ret; |
174 | |
175 | da9062_gpio_set(gc, offset, value); |
176 | |
177 | return 0; |
178 | } |
179 | |
180 | static int da9062_gpio_set_config(struct gpio_chip *gc, unsigned int offset, |
181 | unsigned long config) |
182 | { |
183 | struct da9062_pctl *pctl = gpiochip_get_data(gc); |
184 | struct regmap *regmap = pctl->da9062->regmap; |
185 | int gpio_mode; |
186 | |
187 | /* |
188 | * We need to meet the following restrictions [1, Figure 18]: |
189 | * - PIN_CONFIG_BIAS_PULL_DOWN -> only allowed if the pin is used as |
190 | * gpio input |
191 | * - PIN_CONFIG_BIAS_PULL_UP -> only allowed if the pin is used as |
192 | * gpio output open-drain. |
193 | */ |
194 | |
195 | switch (pinconf_to_config_param(config)) { |
196 | case PIN_CONFIG_BIAS_DISABLE: |
197 | return regmap_update_bits(map: regmap, DA9062AA_CONFIG_K, |
198 | BIT(offset), val: 0); |
199 | case PIN_CONFIG_BIAS_PULL_DOWN: |
200 | gpio_mode = da9062_pctl_get_pin_mode(pctl, offset); |
201 | if (gpio_mode < 0) |
202 | return -EINVAL; |
203 | else if (gpio_mode != DA9062_PIN_GPI) |
204 | return -ENOTSUPP; |
205 | return regmap_update_bits(map: regmap, DA9062AA_CONFIG_K, |
206 | BIT(offset), BIT(offset)); |
207 | case PIN_CONFIG_BIAS_PULL_UP: |
208 | gpio_mode = da9062_pctl_get_pin_mode(pctl, offset); |
209 | if (gpio_mode < 0) |
210 | return -EINVAL; |
211 | else if (gpio_mode != DA9062_PIN_GPO_OD) |
212 | return -ENOTSUPP; |
213 | return regmap_update_bits(map: regmap, DA9062AA_CONFIG_K, |
214 | BIT(offset), BIT(offset)); |
215 | case PIN_CONFIG_DRIVE_OPEN_DRAIN: |
216 | return da9062_pctl_set_pin_mode(pctl, offset, |
217 | DA9062_PIN_GPO_OD); |
218 | case PIN_CONFIG_DRIVE_PUSH_PULL: |
219 | return da9062_pctl_set_pin_mode(pctl, offset, |
220 | DA9062_PIN_GPO_PP); |
221 | default: |
222 | return -ENOTSUPP; |
223 | } |
224 | } |
225 | |
226 | static int da9062_gpio_to_irq(struct gpio_chip *gc, unsigned int offset) |
227 | { |
228 | struct da9062_pctl *pctl = gpiochip_get_data(gc); |
229 | struct da9062 *da9062 = pctl->da9062; |
230 | |
231 | return regmap_irq_get_virq(data: da9062->regmap_irq, |
232 | irq: DA9062_IRQ_GPI0 + offset); |
233 | } |
234 | |
235 | static const struct gpio_chip reference_gc = { |
236 | .owner = THIS_MODULE, |
237 | .get = da9062_gpio_get, |
238 | .set = da9062_gpio_set, |
239 | .get_direction = da9062_gpio_get_direction, |
240 | .direction_input = da9062_gpio_direction_input, |
241 | .direction_output = da9062_gpio_direction_output, |
242 | .set_config = da9062_gpio_set_config, |
243 | .to_irq = da9062_gpio_to_irq, |
244 | .can_sleep = true, |
245 | .ngpio = DA9062_GPIO_NUM, |
246 | .base = -1, |
247 | }; |
248 | |
249 | static int da9062_pctl_probe(struct platform_device *pdev) |
250 | { |
251 | struct device *parent = pdev->dev.parent; |
252 | struct da9062_pctl *pctl; |
253 | int i; |
254 | |
255 | device_set_node(dev: &pdev->dev, dev_fwnode(pdev->dev.parent)); |
256 | |
257 | pctl = devm_kzalloc(dev: &pdev->dev, size: sizeof(*pctl), GFP_KERNEL); |
258 | if (!pctl) |
259 | return -ENOMEM; |
260 | |
261 | pctl->da9062 = dev_get_drvdata(dev: parent); |
262 | if (!pctl->da9062) |
263 | return -EINVAL; |
264 | |
265 | if (!device_property_present(dev: parent, propname: "gpio-controller" )) |
266 | return 0; |
267 | |
268 | for (i = 0; i < ARRAY_SIZE(pctl->pin_config); i++) |
269 | pctl->pin_config[i] = DA9062_PIN_GPO_PP; |
270 | |
271 | /* |
272 | * Currently the driver handles only the GPIO support. The |
273 | * pinctrl/pinmux support can be added later if needed. |
274 | */ |
275 | pctl->gc = reference_gc; |
276 | pctl->gc.label = dev_name(dev: &pdev->dev); |
277 | pctl->gc.parent = &pdev->dev; |
278 | |
279 | platform_set_drvdata(pdev, data: pctl); |
280 | |
281 | return devm_gpiochip_add_data(&pdev->dev, &pctl->gc, pctl); |
282 | } |
283 | |
284 | static struct platform_driver da9062_pctl_driver = { |
285 | .probe = da9062_pctl_probe, |
286 | .driver = { |
287 | .name = "da9062-gpio" , |
288 | }, |
289 | }; |
290 | module_platform_driver(da9062_pctl_driver); |
291 | |
292 | MODULE_AUTHOR("Marco Felsch <kernel@pengutronix.de>" ); |
293 | MODULE_DESCRIPTION("DA9062 PMIC pinctrl and GPIO Driver" ); |
294 | MODULE_LICENSE("GPL v2" ); |
295 | MODULE_ALIAS("platform:da9062-gpio" ); |
296 | |