aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2008-10-10 10:58:12 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2008-10-13 16:51:55 -0400
commit0e7203933224cbe09b5a9125f55b177b8dd5b1bd (patch)
treea0353af32d8a45163885df722baa96c9090ec7a3
parentc661a0b92d487ac20cc9cddbb8f4d40e4dcdbec1 (diff)
mfd: Add GPIO pin configuration support for WM8350
The WM8350 provides a number of user-configurable pins providing access to various signals generated by the functions on the chip. These are referred to as GPIO pins in the device documentation but in Linux terms they are more general than that, providing configuration of alternate functions. This patch implements support for selecting the alternate functions for these pins. They can also be used as GPIOs in the normal Linux sense - a subsequent patch will add support for doing so. This code was all written by Liam Girdwood and has had minor updates and rearrangements by Mark Brown. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Samuel Ortiz <sameo@openedhand.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
-rw-r--r--drivers/mfd/Makefile2
-rw-r--r--drivers/mfd/wm8350-gpio.c222
-rw-r--r--include/linux/mfd/wm8350/gpio.h10
3 files changed, 233 insertions, 1 deletions
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 45038aed2d3..759b1fe1c89 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o
13obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o 13obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o
14 14
15obj-$(CONFIG_MFD_WM8400) += wm8400-core.o 15obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
16wm8350-objs := wm8350-core.o wm8350-regmap.o 16wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
17obj-$(CONFIG_MFD_WM8350) += wm8350.o 17obj-$(CONFIG_MFD_WM8350) += wm8350.o
18obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o 18obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
19 19
diff --git a/drivers/mfd/wm8350-gpio.c b/drivers/mfd/wm8350-gpio.c
new file mode 100644
index 00000000000..ebf99bef392
--- /dev/null
+++ b/drivers/mfd/wm8350-gpio.c
@@ -0,0 +1,222 @@
1/*
2 * wm8350-core.c -- Device access for Wolfson WM8350
3 *
4 * Copyright 2007, 2008 Wolfson Microelectronics PLC.
5 *
6 * Author: Liam Girdwood
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/errno.h>
18
19#include <linux/mfd/wm8350/core.h>
20#include <linux/mfd/wm8350/gpio.h>
21#include <linux/mfd/wm8350/pmic.h>
22
23static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir)
24{
25 int ret;
26
27 wm8350_reg_unlock(wm8350);
28 if (dir == WM8350_GPIO_DIR_OUT)
29 ret = wm8350_clear_bits(wm8350,
30 WM8350_GPIO_CONFIGURATION_I_O,
31 1 << gpio);
32 else
33 ret = wm8350_set_bits(wm8350,
34 WM8350_GPIO_CONFIGURATION_I_O,
35 1 << gpio);
36 wm8350_reg_lock(wm8350);
37 return ret;
38}
39
40static int gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db)
41{
42 if (db == WM8350_GPIO_DEBOUNCE_ON)
43 return wm8350_set_bits(wm8350, WM8350_GPIO_DEBOUNCE,
44 1 << gpio);
45 else
46 return wm8350_clear_bits(wm8350,
47 WM8350_GPIO_DEBOUNCE, 1 << gpio);
48}
49
50static int gpio_set_func(struct wm8350 *wm8350, int gpio, int func)
51{
52 u16 reg;
53
54 wm8350_reg_unlock(wm8350);
55 switch (gpio) {
56 case 0:
57 reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
58 & ~WM8350_GP0_FN_MASK;
59 wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
60 reg | ((func & 0xf) << 0));
61 break;
62 case 1:
63 reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
64 & ~WM8350_GP1_FN_MASK;
65 wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
66 reg | ((func & 0xf) << 4));
67 break;
68 case 2:
69 reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
70 & ~WM8350_GP2_FN_MASK;
71 wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
72 reg | ((func & 0xf) << 8));
73 break;
74 case 3:
75 reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
76 & ~WM8350_GP3_FN_MASK;
77 wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
78 reg | ((func & 0xf) << 12));
79 break;
80 case 4:
81 reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
82 & ~WM8350_GP4_FN_MASK;
83 wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
84 reg | ((func & 0xf) << 0));
85 break;
86 case 5:
87 reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
88 & ~WM8350_GP5_FN_MASK;
89 wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
90 reg | ((func & 0xf) << 4));
91 break;
92 case 6:
93 reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
94 & ~WM8350_GP6_FN_MASK;
95 wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
96 reg | ((func & 0xf) << 8));
97 break;
98 case 7:
99 reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
100 & ~WM8350_GP7_FN_MASK;
101 wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
102 reg | ((func & 0xf) << 12));
103 break;
104 case 8:
105 reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
106 & ~WM8350_GP8_FN_MASK;
107 wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
108 reg | ((func & 0xf) << 0));
109 break;
110 case 9:
111 reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
112 & ~WM8350_GP9_FN_MASK;
113 wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
114 reg | ((func & 0xf) << 4));
115 break;
116 case 10:
117 reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
118 & ~WM8350_GP10_FN_MASK;
119 wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
120 reg | ((func & 0xf) << 8));
121 break;
122 case 11:
123 reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
124 & ~WM8350_GP11_FN_MASK;
125 wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
126 reg | ((func & 0xf) << 12));
127 break;
128 case 12:
129 reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_4)
130 & ~WM8350_GP12_FN_MASK;
131 wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_4,
132 reg | ((func & 0xf) << 0));
133 break;
134 default:
135 wm8350_reg_lock(wm8350);
136 return -EINVAL;
137 }
138
139 wm8350_reg_lock(wm8350);
140 return 0;
141}
142
143static int gpio_set_pull_up(struct wm8350 *wm8350, int gpio, int up)
144{
145 if (up)
146 return wm8350_set_bits(wm8350,
147 WM8350_GPIO_PIN_PULL_UP_CONTROL,
148 1 << gpio);
149 else
150 return wm8350_clear_bits(wm8350,
151 WM8350_GPIO_PIN_PULL_UP_CONTROL,
152 1 << gpio);
153}
154
155static int gpio_set_pull_down(struct wm8350 *wm8350, int gpio, int down)
156{
157 if (down)
158 return wm8350_set_bits(wm8350,
159 WM8350_GPIO_PULL_DOWN_CONTROL,
160 1 << gpio);
161 else
162 return wm8350_clear_bits(wm8350,
163 WM8350_GPIO_PULL_DOWN_CONTROL,
164 1 << gpio);
165}
166
167static int gpio_set_polarity(struct wm8350 *wm8350, int gpio, int pol)
168{
169 if (pol == WM8350_GPIO_ACTIVE_HIGH)
170 return wm8350_set_bits(wm8350,
171 WM8350_GPIO_PIN_POLARITY_TYPE,
172 1 << gpio);
173 else
174 return wm8350_clear_bits(wm8350,
175 WM8350_GPIO_PIN_POLARITY_TYPE,
176 1 << gpio);
177}
178
179static int gpio_set_invert(struct wm8350 *wm8350, int gpio, int invert)
180{
181 if (invert == WM8350_GPIO_INVERT_ON)
182 return wm8350_set_bits(wm8350, WM8350_GPIO_INT_MODE, 1 << gpio);
183 else
184 return wm8350_clear_bits(wm8350,
185 WM8350_GPIO_INT_MODE, 1 << gpio);
186}
187
188int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func,
189 int pol, int pull, int invert, int debounce)
190{
191 /* make sure we never pull up and down at the same time */
192 if (pull == WM8350_GPIO_PULL_NONE) {
193 if (gpio_set_pull_up(wm8350, gpio, 0))
194 goto err;
195 if (gpio_set_pull_down(wm8350, gpio, 0))
196 goto err;
197 } else if (pull == WM8350_GPIO_PULL_UP) {
198 if (gpio_set_pull_down(wm8350, gpio, 0))
199 goto err;
200 if (gpio_set_pull_up(wm8350, gpio, 1))
201 goto err;
202 } else if (pull == WM8350_GPIO_PULL_DOWN) {
203 if (gpio_set_pull_up(wm8350, gpio, 0))
204 goto err;
205 if (gpio_set_pull_down(wm8350, gpio, 1))
206 goto err;
207 }
208
209 if (gpio_set_invert(wm8350, gpio, invert))
210 goto err;
211 if (gpio_set_polarity(wm8350, gpio, pol))
212 goto err;
213 if (gpio_set_debounce(wm8350, gpio, debounce))
214 goto err;
215 if (gpio_set_dir(wm8350, gpio, dir))
216 goto err;
217 return gpio_set_func(wm8350, gpio, func);
218
219err:
220 return -EIO;
221}
222EXPORT_SYMBOL_GPL(wm8350_gpio_config);
diff --git a/include/linux/mfd/wm8350/gpio.h b/include/linux/mfd/wm8350/gpio.h
index 928aa6e91e3..c6cd2ca8854 100644
--- a/include/linux/mfd/wm8350/gpio.h
+++ b/include/linux/mfd/wm8350/gpio.h
@@ -323,4 +323,14 @@
323#define WM8350_GP1_LVL 0x0002 323#define WM8350_GP1_LVL 0x0002
324#define WM8350_GP0_LVL 0x0001 324#define WM8350_GP0_LVL 0x0001
325 325
326struct wm8350;
327
328int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func,
329 int pol, int pull, int invert, int debounce);
330
331/*
332 * GPIO Interrupts
333 */
334#define WM8350_IRQ_GPIO(x) (50 + x)
335
326#endif 336#endif