xref: /linux/drivers/gpio/gpio-wm831x.c (revision 2956b5d94a76b596fa5057c2b3ca915cb27d7652)
1e4b736f1SMark Brown /*
2c103de24SGrant Likely  * gpiolib support for Wolfson WM831x PMICs
3e4b736f1SMark Brown  *
4e4b736f1SMark Brown  * Copyright 2009 Wolfson Microelectronics PLC.
5e4b736f1SMark Brown  *
6e4b736f1SMark Brown  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7e4b736f1SMark Brown  *
8e4b736f1SMark Brown  *  This program is free software; you can redistribute  it and/or modify it
9e4b736f1SMark Brown  *  under  the terms of  the GNU General  Public License as published by the
10e4b736f1SMark Brown  *  Free Software Foundation;  either version 2 of the  License, or (at your
11e4b736f1SMark Brown  *  option) any later version.
12e4b736f1SMark Brown  *
13e4b736f1SMark Brown  */
14e4b736f1SMark Brown 
15e4b736f1SMark Brown #include <linux/kernel.h>
165a0e3ad6STejun Heo #include <linux/slab.h>
17e4b736f1SMark Brown #include <linux/module.h>
18e4b736f1SMark Brown #include <linux/gpio.h>
19e4b736f1SMark Brown #include <linux/mfd/core.h>
20e4b736f1SMark Brown #include <linux/platform_device.h>
21e4b736f1SMark Brown #include <linux/seq_file.h>
22e4b736f1SMark Brown 
23e4b736f1SMark Brown #include <linux/mfd/wm831x/core.h>
24e4b736f1SMark Brown #include <linux/mfd/wm831x/pdata.h>
25e4b736f1SMark Brown #include <linux/mfd/wm831x/gpio.h>
26dc0fb25cSMark Brown #include <linux/mfd/wm831x/irq.h>
27e4b736f1SMark Brown 
28e4b736f1SMark Brown struct wm831x_gpio {
29e4b736f1SMark Brown 	struct wm831x *wm831x;
30e4b736f1SMark Brown 	struct gpio_chip gpio_chip;
31e4b736f1SMark Brown };
32e4b736f1SMark Brown 
33e4b736f1SMark Brown static int wm831x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
34e4b736f1SMark Brown {
359b3c817bSLinus Walleij 	struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
36e4b736f1SMark Brown 	struct wm831x *wm831x = wm831x_gpio->wm831x;
37f92e8f81SMark Brown 	int val = WM831X_GPN_DIR;
38f92e8f81SMark Brown 
39f92e8f81SMark Brown 	if (wm831x->has_gpio_ena)
40f92e8f81SMark Brown 		val |= WM831X_GPN_TRI;
41e4b736f1SMark Brown 
42e4b736f1SMark Brown 	return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset,
431bca748cSMark Brown 			       WM831X_GPN_DIR | WM831X_GPN_TRI |
441bca748cSMark Brown 			       WM831X_GPN_FN_MASK, val);
45e4b736f1SMark Brown }
46e4b736f1SMark Brown 
47e4b736f1SMark Brown static int wm831x_gpio_get(struct gpio_chip *chip, unsigned offset)
48e4b736f1SMark Brown {
499b3c817bSLinus Walleij 	struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
50e4b736f1SMark Brown 	struct wm831x *wm831x = wm831x_gpio->wm831x;
51e4b736f1SMark Brown 	int ret;
52e4b736f1SMark Brown 
53e4b736f1SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_GPIO_LEVEL);
54e4b736f1SMark Brown 	if (ret < 0)
55e4b736f1SMark Brown 		return ret;
56e4b736f1SMark Brown 
57e4b736f1SMark Brown 	if (ret & 1 << offset)
58e4b736f1SMark Brown 		return 1;
59e4b736f1SMark Brown 	else
60e4b736f1SMark Brown 		return 0;
61e4b736f1SMark Brown }
62e4b736f1SMark Brown 
63e4b736f1SMark Brown static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
64e4b736f1SMark Brown {
659b3c817bSLinus Walleij 	struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
66e4b736f1SMark Brown 	struct wm831x *wm831x = wm831x_gpio->wm831x;
67e4b736f1SMark Brown 
68e4b736f1SMark Brown 	wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << offset,
69e4b736f1SMark Brown 			value << offset);
70e4b736f1SMark Brown }
71e4b736f1SMark Brown 
723383d23dSMark Brown static int wm831x_gpio_direction_out(struct gpio_chip *chip,
733383d23dSMark Brown 				     unsigned offset, int value)
743383d23dSMark Brown {
759b3c817bSLinus Walleij 	struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
763383d23dSMark Brown 	struct wm831x *wm831x = wm831x_gpio->wm831x;
77f92e8f81SMark Brown 	int val = 0;
783383d23dSMark Brown 	int ret;
793383d23dSMark Brown 
80f92e8f81SMark Brown 	if (wm831x->has_gpio_ena)
81f92e8f81SMark Brown 		val |= WM831X_GPN_TRI;
82f92e8f81SMark Brown 
833383d23dSMark Brown 	ret = wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset,
841bca748cSMark Brown 			      WM831X_GPN_DIR | WM831X_GPN_TRI |
851bca748cSMark Brown 			      WM831X_GPN_FN_MASK, val);
863383d23dSMark Brown 	if (ret < 0)
873383d23dSMark Brown 		return ret;
883383d23dSMark Brown 
893383d23dSMark Brown 	/* Can only set GPIO state once it's in output mode */
903383d23dSMark Brown 	wm831x_gpio_set(chip, offset, value);
913383d23dSMark Brown 
923383d23dSMark Brown 	return 0;
933383d23dSMark Brown }
943383d23dSMark Brown 
95dc0fb25cSMark Brown static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
96dc0fb25cSMark Brown {
979b3c817bSLinus Walleij 	struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
98dc0fb25cSMark Brown 	struct wm831x *wm831x = wm831x_gpio->wm831x;
99dc0fb25cSMark Brown 
100cd99758bSMark Brown 	return irq_create_mapping(wm831x->irq_domain,
101cd99758bSMark Brown 				  WM831X_IRQ_GPIO_1 + offset);
102dc0fb25cSMark Brown }
103dc0fb25cSMark Brown 
104*2956b5d9SMika Westerberg static int wm831x_gpio_set_debounce(struct wm831x *wm831x, unsigned offset,
105b12c35e2SMark Brown 				    unsigned debounce)
106b12c35e2SMark Brown {
107b12c35e2SMark Brown 	int reg = WM831X_GPIO1_CONTROL + offset;
108b12c35e2SMark Brown 	int ret, fn;
109b12c35e2SMark Brown 
110b12c35e2SMark Brown 	ret = wm831x_reg_read(wm831x, reg);
111b12c35e2SMark Brown 	if (ret < 0)
112b12c35e2SMark Brown 		return ret;
113b12c35e2SMark Brown 
114b12c35e2SMark Brown 	switch (ret & WM831X_GPN_FN_MASK) {
115b12c35e2SMark Brown 	case 0:
116b12c35e2SMark Brown 	case 1:
117b12c35e2SMark Brown 		break;
118b12c35e2SMark Brown 	default:
119b12c35e2SMark Brown 		/* Not in GPIO mode */
120b12c35e2SMark Brown 		return -EBUSY;
121b12c35e2SMark Brown 	}
122b12c35e2SMark Brown 
123b12c35e2SMark Brown 	if (debounce >= 32 && debounce <= 64)
124b12c35e2SMark Brown 		fn = 0;
125b12c35e2SMark Brown 	else if (debounce >= 4000 && debounce <= 8000)
126b12c35e2SMark Brown 		fn = 1;
127b12c35e2SMark Brown 	else
128b12c35e2SMark Brown 		return -EINVAL;
129b12c35e2SMark Brown 
130b12c35e2SMark Brown 	return wm831x_set_bits(wm831x, reg, WM831X_GPN_FN_MASK, fn);
131b12c35e2SMark Brown }
132b12c35e2SMark Brown 
133*2956b5d9SMika Westerberg static int wm831x_set_config(struct gpio_chip *chip, unsigned int offset,
134*2956b5d9SMika Westerberg 			     unsigned long config)
13551c27da1SLinus Walleij {
13651c27da1SLinus Walleij 	struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
13751c27da1SLinus Walleij 	struct wm831x *wm831x = wm831x_gpio->wm831x;
13851c27da1SLinus Walleij 	int reg = WM831X_GPIO1_CONTROL + offset;
13951c27da1SLinus Walleij 
140*2956b5d9SMika Westerberg 	switch (pinconf_to_config_param(config)) {
141*2956b5d9SMika Westerberg 	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
14251c27da1SLinus Walleij 		return wm831x_set_bits(wm831x, reg,
14351c27da1SLinus Walleij 				       WM831X_GPN_OD_MASK, WM831X_GPN_OD);
144*2956b5d9SMika Westerberg 	case PIN_CONFIG_DRIVE_PUSH_PULL:
14551c27da1SLinus Walleij 		return wm831x_set_bits(wm831x, reg,
14651c27da1SLinus Walleij 				       WM831X_GPN_OD_MASK, 0);
147*2956b5d9SMika Westerberg 	case PIN_CONFIG_INPUT_DEBOUNCE:
148*2956b5d9SMika Westerberg 		return wm831x_gpio_set_debounce(wm831x, offset,
149*2956b5d9SMika Westerberg 			pinconf_to_config_argument(config));
15051c27da1SLinus Walleij 	default:
15151c27da1SLinus Walleij 		break;
15251c27da1SLinus Walleij 	}
15351c27da1SLinus Walleij 
15451c27da1SLinus Walleij 	return -ENOTSUPP;
15551c27da1SLinus Walleij }
15651c27da1SLinus Walleij 
157e4b736f1SMark Brown #ifdef CONFIG_DEBUG_FS
158e4b736f1SMark Brown static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
159e4b736f1SMark Brown {
1609b3c817bSLinus Walleij 	struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
161e4b736f1SMark Brown 	struct wm831x *wm831x = wm831x_gpio->wm831x;
162f92e8f81SMark Brown 	int i, tristated;
163e4b736f1SMark Brown 
164e4b736f1SMark Brown 	for (i = 0; i < chip->ngpio; i++) {
165e4b736f1SMark Brown 		int gpio = i + chip->base;
166e4b736f1SMark Brown 		int reg;
167e4b736f1SMark Brown 		const char *label, *pull, *powerdomain;
168e4b736f1SMark Brown 
169e4b736f1SMark Brown 		/* We report the GPIO even if it's not requested since
170e4b736f1SMark Brown 		 * we're also reporting things like alternate
171e4b736f1SMark Brown 		 * functions which apply even when the GPIO is not in
172e4b736f1SMark Brown 		 * use as a GPIO.
173e4b736f1SMark Brown 		 */
174e4b736f1SMark Brown 		label = gpiochip_is_requested(chip, i);
175e4b736f1SMark Brown 		if (!label)
176e4b736f1SMark Brown 			label = "Unrequested";
177e4b736f1SMark Brown 
178e4b736f1SMark Brown 		seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, label);
179e4b736f1SMark Brown 
180e4b736f1SMark Brown 		reg = wm831x_reg_read(wm831x, WM831X_GPIO1_CONTROL + i);
181e4b736f1SMark Brown 		if (reg < 0) {
182e4b736f1SMark Brown 			dev_err(wm831x->dev,
183e4b736f1SMark Brown 				"GPIO control %d read failed: %d\n",
184e4b736f1SMark Brown 				gpio, reg);
185e4b736f1SMark Brown 			seq_printf(s, "\n");
186e4b736f1SMark Brown 			continue;
187e4b736f1SMark Brown 		}
188e4b736f1SMark Brown 
189e4b736f1SMark Brown 		switch (reg & WM831X_GPN_PULL_MASK) {
190e4b736f1SMark Brown 		case WM831X_GPIO_PULL_NONE:
191e4b736f1SMark Brown 			pull = "nopull";
192e4b736f1SMark Brown 			break;
193e4b736f1SMark Brown 		case WM831X_GPIO_PULL_DOWN:
194e4b736f1SMark Brown 			pull = "pulldown";
195e4b736f1SMark Brown 			break;
196e4b736f1SMark Brown 		case WM831X_GPIO_PULL_UP:
197e4b736f1SMark Brown 			pull = "pullup";
198164d5c39SAxel Lin 			break;
199e4b736f1SMark Brown 		default:
200e4b736f1SMark Brown 			pull = "INVALID PULL";
201e4b736f1SMark Brown 			break;
202e4b736f1SMark Brown 		}
203e4b736f1SMark Brown 
204e4b736f1SMark Brown 		switch (i + 1) {
205e4b736f1SMark Brown 		case 1 ... 3:
206e4b736f1SMark Brown 		case 7 ... 9:
207e4b736f1SMark Brown 			if (reg & WM831X_GPN_PWR_DOM)
208e4b736f1SMark Brown 				powerdomain = "VPMIC";
209e4b736f1SMark Brown 			else
210e4b736f1SMark Brown 				powerdomain = "DBVDD";
211e4b736f1SMark Brown 			break;
212e4b736f1SMark Brown 
213e4b736f1SMark Brown 		case 4 ... 6:
214e4b736f1SMark Brown 		case 10 ... 12:
215e4b736f1SMark Brown 			if (reg & WM831X_GPN_PWR_DOM)
216e4b736f1SMark Brown 				powerdomain = "SYSVDD";
217e4b736f1SMark Brown 			else
218e4b736f1SMark Brown 				powerdomain = "DBVDD";
219e4b736f1SMark Brown 			break;
220e4b736f1SMark Brown 
221e4b736f1SMark Brown 		case 13 ... 16:
222e4b736f1SMark Brown 			powerdomain = "TPVDD";
223e4b736f1SMark Brown 			break;
224e4b736f1SMark Brown 
225e4b736f1SMark Brown 		default:
226e4b736f1SMark Brown 			BUG();
227e4b736f1SMark Brown 			break;
228e4b736f1SMark Brown 		}
229e4b736f1SMark Brown 
230f92e8f81SMark Brown 		tristated = reg & WM831X_GPN_TRI;
231f92e8f81SMark Brown 		if (wm831x->has_gpio_ena)
232f92e8f81SMark Brown 			tristated = !tristated;
233f92e8f81SMark Brown 
234e4b736f1SMark Brown 		seq_printf(s, " %s %s %s %s%s\n"
235e4b736f1SMark Brown 			   "                                  %s%s (0x%4x)\n",
236e4b736f1SMark Brown 			   reg & WM831X_GPN_DIR ? "in" : "out",
237e4b736f1SMark Brown 			   wm831x_gpio_get(chip, i) ? "high" : "low",
238e4b736f1SMark Brown 			   pull,
239e4b736f1SMark Brown 			   powerdomain,
2406b8274faSMark Brown 			   reg & WM831X_GPN_POL ? "" : " inverted",
24151c27da1SLinus Walleij 			   reg & WM831X_GPN_OD ? "open-drain" : "push-pull",
242f92e8f81SMark Brown 			   tristated ? " tristated" : "",
243e4b736f1SMark Brown 			   reg);
244e4b736f1SMark Brown 	}
245e4b736f1SMark Brown }
246e4b736f1SMark Brown #else
247e4b736f1SMark Brown #define wm831x_gpio_dbg_show NULL
248e4b736f1SMark Brown #endif
249e4b736f1SMark Brown 
250e35b5ab0SJulia Lawall static const struct gpio_chip template_chip = {
251e4b736f1SMark Brown 	.label			= "wm831x",
252e4b736f1SMark Brown 	.owner			= THIS_MODULE,
253e4b736f1SMark Brown 	.direction_input	= wm831x_gpio_direction_in,
254e4b736f1SMark Brown 	.get			= wm831x_gpio_get,
255e4b736f1SMark Brown 	.direction_output	= wm831x_gpio_direction_out,
256e4b736f1SMark Brown 	.set			= wm831x_gpio_set,
257dc0fb25cSMark Brown 	.to_irq			= wm831x_gpio_to_irq,
258*2956b5d9SMika Westerberg 	.set_config		= wm831x_set_config,
259e4b736f1SMark Brown 	.dbg_show		= wm831x_gpio_dbg_show,
2609fb1f39eSLinus Walleij 	.can_sleep		= true,
261e4b736f1SMark Brown };
262e4b736f1SMark Brown 
2633836309dSBill Pemberton static int wm831x_gpio_probe(struct platform_device *pdev)
264e4b736f1SMark Brown {
265e4b736f1SMark Brown 	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
266e56aee18SJingoo Han 	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
267e4b736f1SMark Brown 	struct wm831x_gpio *wm831x_gpio;
268e4b736f1SMark Brown 	int ret;
269e4b736f1SMark Brown 
270718bc6e3SAxel Lin 	wm831x_gpio = devm_kzalloc(&pdev->dev, sizeof(*wm831x_gpio),
271718bc6e3SAxel Lin 				   GFP_KERNEL);
272e4b736f1SMark Brown 	if (wm831x_gpio == NULL)
273e4b736f1SMark Brown 		return -ENOMEM;
274e4b736f1SMark Brown 
275e4b736f1SMark Brown 	wm831x_gpio->wm831x = wm831x;
276e4b736f1SMark Brown 	wm831x_gpio->gpio_chip = template_chip;
2776f2ecaaeSMark Brown 	wm831x_gpio->gpio_chip.ngpio = wm831x->num_gpio;
27858383c78SLinus Walleij 	wm831x_gpio->gpio_chip.parent = &pdev->dev;
279e4b736f1SMark Brown 	if (pdata && pdata->gpio_base)
280e4b736f1SMark Brown 		wm831x_gpio->gpio_chip.base = pdata->gpio_base;
281e4b736f1SMark Brown 	else
282e4b736f1SMark Brown 		wm831x_gpio->gpio_chip.base = -1;
283e4b736f1SMark Brown 
28461da4848SLaxman Dewangan 	ret = devm_gpiochip_add_data(&pdev->dev, &wm831x_gpio->gpio_chip,
28561da4848SLaxman Dewangan 				     wm831x_gpio);
286e4b736f1SMark Brown 	if (ret < 0) {
287718bc6e3SAxel Lin 		dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
288718bc6e3SAxel Lin 		return ret;
289e4b736f1SMark Brown 	}
290e4b736f1SMark Brown 
291e4b736f1SMark Brown 	platform_set_drvdata(pdev, wm831x_gpio);
292e4b736f1SMark Brown 
293e4b736f1SMark Brown 	return ret;
294e4b736f1SMark Brown }
295e4b736f1SMark Brown 
296e4b736f1SMark Brown static struct platform_driver wm831x_gpio_driver = {
297e4b736f1SMark Brown 	.driver.name	= "wm831x-gpio",
298e4b736f1SMark Brown 	.probe		= wm831x_gpio_probe,
299e4b736f1SMark Brown };
300e4b736f1SMark Brown 
301e4b736f1SMark Brown static int __init wm831x_gpio_init(void)
302e4b736f1SMark Brown {
303e4b736f1SMark Brown 	return platform_driver_register(&wm831x_gpio_driver);
304e4b736f1SMark Brown }
305e4b736f1SMark Brown subsys_initcall(wm831x_gpio_init);
306e4b736f1SMark Brown 
307e4b736f1SMark Brown static void __exit wm831x_gpio_exit(void)
308e4b736f1SMark Brown {
309e4b736f1SMark Brown 	platform_driver_unregister(&wm831x_gpio_driver);
310e4b736f1SMark Brown }
311e4b736f1SMark Brown module_exit(wm831x_gpio_exit);
312e4b736f1SMark Brown 
313e4b736f1SMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
314e4b736f1SMark Brown MODULE_DESCRIPTION("GPIO interface for WM831x PMICs");
315e4b736f1SMark Brown MODULE_LICENSE("GPL");
316e4b736f1SMark Brown MODULE_ALIAS("platform:wm831x-gpio");
317