1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * gpiolib support for Wolfson WM831x PMICs |
4 | * |
5 | * Copyright 2009 Wolfson Microelectronics PLC. |
6 | * |
7 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
8 | * |
9 | */ |
10 | |
11 | #include <linux/kernel.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/module.h> |
14 | #include <linux/gpio/driver.h> |
15 | #include <linux/mfd/core.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/seq_file.h> |
18 | |
19 | #include <linux/mfd/wm831x/core.h> |
20 | #include <linux/mfd/wm831x/pdata.h> |
21 | #include <linux/mfd/wm831x/gpio.h> |
22 | #include <linux/mfd/wm831x/irq.h> |
23 | |
24 | struct wm831x_gpio { |
25 | struct wm831x *wm831x; |
26 | struct gpio_chip gpio_chip; |
27 | }; |
28 | |
29 | static int wm831x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) |
30 | { |
31 | struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(gc: chip); |
32 | struct wm831x *wm831x = wm831x_gpio->wm831x; |
33 | int val = WM831X_GPN_DIR; |
34 | |
35 | if (wm831x->has_gpio_ena) |
36 | val |= WM831X_GPN_TRI; |
37 | |
38 | return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset, |
39 | WM831X_GPN_DIR | WM831X_GPN_TRI | |
40 | WM831X_GPN_FN_MASK, val); |
41 | } |
42 | |
43 | static int wm831x_gpio_get(struct gpio_chip *chip, unsigned offset) |
44 | { |
45 | struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(gc: chip); |
46 | struct wm831x *wm831x = wm831x_gpio->wm831x; |
47 | int ret; |
48 | |
49 | ret = wm831x_reg_read(wm831x, WM831X_GPIO_LEVEL); |
50 | if (ret < 0) |
51 | return ret; |
52 | |
53 | if (ret & 1 << offset) |
54 | return 1; |
55 | else |
56 | return 0; |
57 | } |
58 | |
59 | static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) |
60 | { |
61 | struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(gc: chip); |
62 | struct wm831x *wm831x = wm831x_gpio->wm831x; |
63 | |
64 | wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, mask: 1 << offset, |
65 | val: value << offset); |
66 | } |
67 | |
68 | static int wm831x_gpio_direction_out(struct gpio_chip *chip, |
69 | unsigned offset, int value) |
70 | { |
71 | struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(gc: chip); |
72 | struct wm831x *wm831x = wm831x_gpio->wm831x; |
73 | int val = 0; |
74 | int ret; |
75 | |
76 | if (wm831x->has_gpio_ena) |
77 | val |= WM831X_GPN_TRI; |
78 | |
79 | ret = wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset, |
80 | WM831X_GPN_DIR | WM831X_GPN_TRI | |
81 | WM831X_GPN_FN_MASK, val); |
82 | if (ret < 0) |
83 | return ret; |
84 | |
85 | /* Can only set GPIO state once it's in output mode */ |
86 | wm831x_gpio_set(chip, offset, value); |
87 | |
88 | return 0; |
89 | } |
90 | |
91 | static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) |
92 | { |
93 | struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(gc: chip); |
94 | struct wm831x *wm831x = wm831x_gpio->wm831x; |
95 | |
96 | return irq_create_mapping(host: wm831x->irq_domain, |
97 | WM831X_IRQ_GPIO_1 + offset); |
98 | } |
99 | |
100 | static int wm831x_gpio_set_debounce(struct wm831x *wm831x, unsigned offset, |
101 | unsigned debounce) |
102 | { |
103 | int reg = WM831X_GPIO1_CONTROL + offset; |
104 | int ret, fn; |
105 | |
106 | ret = wm831x_reg_read(wm831x, reg); |
107 | if (ret < 0) |
108 | return ret; |
109 | |
110 | switch (ret & WM831X_GPN_FN_MASK) { |
111 | case 0: |
112 | case 1: |
113 | break; |
114 | default: |
115 | /* Not in GPIO mode */ |
116 | return -EBUSY; |
117 | } |
118 | |
119 | if (debounce >= 32 && debounce <= 64) |
120 | fn = 0; |
121 | else if (debounce >= 4000 && debounce <= 8000) |
122 | fn = 1; |
123 | else |
124 | return -EINVAL; |
125 | |
126 | return wm831x_set_bits(wm831x, reg, WM831X_GPN_FN_MASK, val: fn); |
127 | } |
128 | |
129 | static int wm831x_set_config(struct gpio_chip *chip, unsigned int offset, |
130 | unsigned long config) |
131 | { |
132 | struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(gc: chip); |
133 | struct wm831x *wm831x = wm831x_gpio->wm831x; |
134 | int reg = WM831X_GPIO1_CONTROL + offset; |
135 | |
136 | switch (pinconf_to_config_param(config)) { |
137 | case PIN_CONFIG_DRIVE_OPEN_DRAIN: |
138 | return wm831x_set_bits(wm831x, reg, |
139 | WM831X_GPN_OD_MASK, WM831X_GPN_OD); |
140 | case PIN_CONFIG_DRIVE_PUSH_PULL: |
141 | return wm831x_set_bits(wm831x, reg, |
142 | WM831X_GPN_OD_MASK, val: 0); |
143 | case PIN_CONFIG_INPUT_DEBOUNCE: |
144 | return wm831x_gpio_set_debounce(wm831x, offset, |
145 | debounce: pinconf_to_config_argument(config)); |
146 | default: |
147 | break; |
148 | } |
149 | |
150 | return -ENOTSUPP; |
151 | } |
152 | |
153 | #ifdef CONFIG_DEBUG_FS |
154 | static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) |
155 | { |
156 | struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(gc: chip); |
157 | struct wm831x *wm831x = wm831x_gpio->wm831x; |
158 | int i, tristated; |
159 | |
160 | for (i = 0; i < chip->ngpio; i++) { |
161 | int gpio = i + chip->base; |
162 | int reg; |
163 | const char *label, *pull, *powerdomain; |
164 | |
165 | /* We report the GPIO even if it's not requested since |
166 | * we're also reporting things like alternate |
167 | * functions which apply even when the GPIO is not in |
168 | * use as a GPIO. |
169 | */ |
170 | label = gpiochip_is_requested(gc: chip, offset: i); |
171 | if (!label) |
172 | label = "Unrequested" ; |
173 | |
174 | seq_printf(m: s, fmt: " gpio-%-3d (%-20.20s) " , gpio, label); |
175 | |
176 | reg = wm831x_reg_read(wm831x, WM831X_GPIO1_CONTROL + i); |
177 | if (reg < 0) { |
178 | dev_err(wm831x->dev, |
179 | "GPIO control %d read failed: %d\n" , |
180 | gpio, reg); |
181 | seq_putc(m: s, c: '\n'); |
182 | continue; |
183 | } |
184 | |
185 | switch (reg & WM831X_GPN_PULL_MASK) { |
186 | case WM831X_GPIO_PULL_NONE: |
187 | pull = "nopull" ; |
188 | break; |
189 | case WM831X_GPIO_PULL_DOWN: |
190 | pull = "pulldown" ; |
191 | break; |
192 | case WM831X_GPIO_PULL_UP: |
193 | pull = "pullup" ; |
194 | break; |
195 | default: |
196 | pull = "INVALID PULL" ; |
197 | break; |
198 | } |
199 | |
200 | switch (i + 1) { |
201 | case 1 ... 3: |
202 | case 7 ... 9: |
203 | if (reg & WM831X_GPN_PWR_DOM) |
204 | powerdomain = "VPMIC" ; |
205 | else |
206 | powerdomain = "DBVDD" ; |
207 | break; |
208 | |
209 | case 4 ... 6: |
210 | case 10 ... 12: |
211 | if (reg & WM831X_GPN_PWR_DOM) |
212 | powerdomain = "SYSVDD" ; |
213 | else |
214 | powerdomain = "DBVDD" ; |
215 | break; |
216 | |
217 | case 13 ... 16: |
218 | powerdomain = "TPVDD" ; |
219 | break; |
220 | |
221 | default: |
222 | BUG(); |
223 | break; |
224 | } |
225 | |
226 | tristated = reg & WM831X_GPN_TRI; |
227 | if (wm831x->has_gpio_ena) |
228 | tristated = !tristated; |
229 | |
230 | seq_printf(m: s, fmt: " %s %s %s %s%s\n" |
231 | " %s%s (0x%4x)\n" , |
232 | reg & WM831X_GPN_DIR ? "in" : "out" , |
233 | wm831x_gpio_get(chip, offset: i) ? "high" : "low" , |
234 | pull, |
235 | powerdomain, |
236 | reg & WM831X_GPN_POL ? "" : " inverted" , |
237 | reg & WM831X_GPN_OD ? "open-drain" : "push-pull" , |
238 | tristated ? " tristated" : "" , |
239 | reg); |
240 | } |
241 | } |
242 | #else |
243 | #define wm831x_gpio_dbg_show NULL |
244 | #endif |
245 | |
246 | static const struct gpio_chip template_chip = { |
247 | .label = "wm831x" , |
248 | .owner = THIS_MODULE, |
249 | .direction_input = wm831x_gpio_direction_in, |
250 | .get = wm831x_gpio_get, |
251 | .direction_output = wm831x_gpio_direction_out, |
252 | .set = wm831x_gpio_set, |
253 | .to_irq = wm831x_gpio_to_irq, |
254 | .set_config = wm831x_set_config, |
255 | .dbg_show = wm831x_gpio_dbg_show, |
256 | .can_sleep = true, |
257 | }; |
258 | |
259 | static int wm831x_gpio_probe(struct platform_device *pdev) |
260 | { |
261 | struct wm831x *wm831x = dev_get_drvdata(dev: pdev->dev.parent); |
262 | struct wm831x_pdata *pdata = &wm831x->pdata; |
263 | struct wm831x_gpio *wm831x_gpio; |
264 | |
265 | device_set_node(dev: &pdev->dev, dev_fwnode(pdev->dev.parent)); |
266 | |
267 | wm831x_gpio = devm_kzalloc(dev: &pdev->dev, size: sizeof(*wm831x_gpio), |
268 | GFP_KERNEL); |
269 | if (wm831x_gpio == NULL) |
270 | return -ENOMEM; |
271 | |
272 | wm831x_gpio->wm831x = wm831x; |
273 | wm831x_gpio->gpio_chip = template_chip; |
274 | wm831x_gpio->gpio_chip.ngpio = wm831x->num_gpio; |
275 | wm831x_gpio->gpio_chip.parent = &pdev->dev; |
276 | if (pdata && pdata->gpio_base) |
277 | wm831x_gpio->gpio_chip.base = pdata->gpio_base; |
278 | else |
279 | wm831x_gpio->gpio_chip.base = -1; |
280 | |
281 | return devm_gpiochip_add_data(&pdev->dev, &wm831x_gpio->gpio_chip, wm831x_gpio); |
282 | } |
283 | |
284 | static struct platform_driver wm831x_gpio_driver = { |
285 | .driver.name = "wm831x-gpio" , |
286 | .probe = wm831x_gpio_probe, |
287 | }; |
288 | |
289 | static int __init wm831x_gpio_init(void) |
290 | { |
291 | return platform_driver_register(&wm831x_gpio_driver); |
292 | } |
293 | subsys_initcall(wm831x_gpio_init); |
294 | |
295 | static void __exit wm831x_gpio_exit(void) |
296 | { |
297 | platform_driver_unregister(&wm831x_gpio_driver); |
298 | } |
299 | module_exit(wm831x_gpio_exit); |
300 | |
301 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>" ); |
302 | MODULE_DESCRIPTION("GPIO interface for WM831x PMICs" ); |
303 | MODULE_LICENSE("GPL" ); |
304 | MODULE_ALIAS("platform:wm831x-gpio" ); |
305 | |