aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis Turischev <denis@compulab.co.il>2010-03-02 04:48:55 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2010-03-07 16:17:37 -0500
commitbe9b06b2d80fe661491138c6993f944babb26260 (patch)
treeea037fa781ccfbec3a43715ea6362bba38fa44a1
parentfd46a0064af171c90664e5b7165c0c9f94478a87 (diff)
gpio: add Intel SCH GPIO controller driver
Signed-off-by: Denis Turischev <denis@compulab.co.il> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--drivers/gpio/Kconfig16
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/sch_gpio.c282
3 files changed, 299 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f42cb317a779..60cb3632c8fd 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -94,6 +94,22 @@ config GPIO_VR41XX
94 help 94 help
95 Say yes here to support the NEC VR4100 series General-purpose I/O Uint 95 Say yes here to support the NEC VR4100 series General-purpose I/O Uint
96 96
97config GPIO_SCH
98 tristate "Intel SCH GPIO"
99 depends on GPIOLIB
100 select LPC_SCH
101 help
102 Say yes here to support GPIO interface on Intel Poulsbo SCH.
103 The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are
104 powered by the core power rail and are turned off during sleep
105 modes (S3 and higher). The remaining four GPIOs are powered by
106 the Intel SCH suspend power supply. These GPIOs remain
107 active during S3. The suspend powered GPIOs can be used to wake the
108 system from the Suspend-to-RAM state.
109
110 This driver can also be built as a module. If so, the module
111 will be called sch-gpio.
112
97comment "I2C GPIO expanders:" 113comment "I2C GPIO expanders:"
98 114
99config GPIO_MAX7300 115config GPIO_MAX7300
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 594bb70f65af..10f3f8d958b1 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -27,3 +27,4 @@ obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
27obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o 27obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o
28obj-$(CONFIG_GPIO_WM8350) += wm8350-gpiolib.o 28obj-$(CONFIG_GPIO_WM8350) += wm8350-gpiolib.o
29obj-$(CONFIG_GPIO_WM8994) += wm8994-gpio.o 29obj-$(CONFIG_GPIO_WM8994) += wm8994-gpio.o
30obj-$(CONFIG_GPIO_SCH) += sch_gpio.o \ No newline at end of file
diff --git a/drivers/gpio/sch_gpio.c b/drivers/gpio/sch_gpio.c
new file mode 100644
index 000000000000..761071ae3596
--- /dev/null
+++ b/drivers/gpio/sch_gpio.c
@@ -0,0 +1,282 @@
1/*
2 * sch_gpio.c - GPIO interface for Intel Poulsbo SCH
3 *
4 * Copyright (c) 2010 CompuLab Ltd
5 * Author: Denis Turischev <denis@compulab.co.il>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License 2 as published
9 * by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; see the file COPYING. If not, write to
18 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#include <linux/init.h>
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/io.h>
25#include <linux/errno.h>
26#include <linux/acpi.h>
27#include <linux/platform_device.h>
28
29#include <linux/gpio.h>
30
31static DEFINE_SPINLOCK(gpio_lock);
32
33#define CGEN (0x00)
34#define CGIO (0x04)
35#define CGLV (0x08)
36
37#define RGEN (0x20)
38#define RGIO (0x24)
39#define RGLV (0x28)
40
41static unsigned short gpio_ba;
42
43static int sch_gpio_core_direction_in(struct gpio_chip *gc, unsigned gpio_num)
44{
45 u8 curr_dirs;
46 unsigned short offset, bit;
47
48 spin_lock(&gpio_lock);
49
50 offset = CGIO + gpio_num / 8;
51 bit = gpio_num % 8;
52
53 curr_dirs = inb(gpio_ba + offset);
54
55 if (!(curr_dirs & (1 << bit)))
56 outb(curr_dirs | (1 << bit), gpio_ba + offset);
57
58 spin_unlock(&gpio_lock);
59 return 0;
60}
61
62static int sch_gpio_core_get(struct gpio_chip *gc, unsigned gpio_num)
63{
64 int res;
65 unsigned short offset, bit;
66
67 offset = CGLV + gpio_num / 8;
68 bit = gpio_num % 8;
69
70 res = !!(inb(gpio_ba + offset) & (1 << bit));
71 return res;
72}
73
74static void sch_gpio_core_set(struct gpio_chip *gc, unsigned gpio_num, int val)
75{
76 u8 curr_vals;
77 unsigned short offset, bit;
78
79 spin_lock(&gpio_lock);
80
81 offset = CGLV + gpio_num / 8;
82 bit = gpio_num % 8;
83
84 curr_vals = inb(gpio_ba + offset);
85
86 if (val)
87 outb(curr_vals | (1 << bit), gpio_ba + offset);
88 else
89 outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
90 spin_unlock(&gpio_lock);
91}
92
93static int sch_gpio_core_direction_out(struct gpio_chip *gc,
94 unsigned gpio_num, int val)
95{
96 u8 curr_dirs;
97 unsigned short offset, bit;
98
99 sch_gpio_core_set(gc, gpio_num, val);
100
101 spin_lock(&gpio_lock);
102
103 offset = CGIO + gpio_num / 8;
104 bit = gpio_num % 8;
105
106 curr_dirs = inb(gpio_ba + offset);
107 if (curr_dirs & (1 << bit))
108 outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
109
110 spin_unlock(&gpio_lock);
111 return 0;
112}
113
114static struct gpio_chip sch_gpio_core = {
115 .label = "sch_gpio_core",
116 .owner = THIS_MODULE,
117 .direction_input = sch_gpio_core_direction_in,
118 .get = sch_gpio_core_get,
119 .direction_output = sch_gpio_core_direction_out,
120 .set = sch_gpio_core_set,
121};
122
123static int sch_gpio_resume_direction_in(struct gpio_chip *gc,
124 unsigned gpio_num)
125{
126 u8 curr_dirs;
127
128 spin_lock(&gpio_lock);
129
130 curr_dirs = inb(gpio_ba + RGIO);
131
132 if (!(curr_dirs & (1 << gpio_num)))
133 outb(curr_dirs | (1 << gpio_num) , gpio_ba + RGIO);
134
135 spin_unlock(&gpio_lock);
136 return 0;
137}
138
139static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num)
140{
141 return !!(inb(gpio_ba + RGLV) & (1 << gpio_num));
142}
143
144static void sch_gpio_resume_set(struct gpio_chip *gc,
145 unsigned gpio_num, int val)
146{
147 u8 curr_vals;
148
149 spin_lock(&gpio_lock);
150
151 curr_vals = inb(gpio_ba + RGLV);
152
153 if (val)
154 outb(curr_vals | (1 << gpio_num), gpio_ba + RGLV);
155 else
156 outb((curr_vals & ~(1 << gpio_num)), gpio_ba + RGLV);
157
158 spin_unlock(&gpio_lock);
159}
160
161static int sch_gpio_resume_direction_out(struct gpio_chip *gc,
162 unsigned gpio_num, int val)
163{
164 u8 curr_dirs;
165
166 sch_gpio_resume_set(gc, gpio_num, val);
167
168 spin_lock(&gpio_lock);
169
170 curr_dirs = inb(gpio_ba + RGIO);
171 if (curr_dirs & (1 << gpio_num))
172 outb(curr_dirs & ~(1 << gpio_num), gpio_ba + RGIO);
173
174 spin_unlock(&gpio_lock);
175 return 0;
176}
177
178static struct gpio_chip sch_gpio_resume = {
179 .label = "sch_gpio_resume",
180 .owner = THIS_MODULE,
181 .direction_input = sch_gpio_resume_direction_in,
182 .get = sch_gpio_resume_get,
183 .direction_output = sch_gpio_resume_direction_out,
184 .set = sch_gpio_resume_set,
185};
186
187static int __devinit sch_gpio_probe(struct platform_device *pdev)
188{
189 struct resource *res;
190 int err;
191
192 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
193 if (!res)
194 return -EBUSY;
195
196 if (!request_region(res->start, resource_size(res), pdev->name))
197 return -EBUSY;
198
199 gpio_ba = res->start;
200
201 sch_gpio_core.base = 0;
202 sch_gpio_core.ngpio = 10;
203 sch_gpio_core.dev = &pdev->dev;
204
205 sch_gpio_resume.base = 10;
206 sch_gpio_resume.ngpio = 4;
207 sch_gpio_resume.dev = &pdev->dev;
208
209 err = gpiochip_add(&sch_gpio_core);
210 if (err < 0)
211 goto err_sch_gpio_core;
212
213 err = gpiochip_add(&sch_gpio_resume);
214 if (err < 0)
215 goto err_sch_gpio_resume;
216
217 /*
218 * GPIO[6:0] enabled by default
219 * GPIO7 is configured by the CMC as SLPIOVR
220 * Enable GPIO[9:8] core powered gpios explicitly
221 */
222 outb(0x3, gpio_ba + CGEN + 1);
223 /*
224 * SUS_GPIO[2:0] enabled by default
225 * Enable SUS_GPIO3 resume powered gpio explicitly
226 */
227 outb(0x8, gpio_ba + RGEN);
228
229 return 0;
230
231err_sch_gpio_resume:
232 gpiochip_remove(&sch_gpio_core);
233
234err_sch_gpio_core:
235 release_region(res->start, resource_size(res));
236 gpio_ba = 0;
237
238 return err;
239}
240
241static int __devexit sch_gpio_remove(struct platform_device *pdev)
242{
243 struct resource *res;
244 if (gpio_ba) {
245 gpiochip_remove(&sch_gpio_core);
246 gpiochip_remove(&sch_gpio_resume);
247
248 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
249
250 release_region(res->start, resource_size(res));
251 gpio_ba = 0;
252 }
253
254 return 0;
255}
256
257static struct platform_driver sch_gpio_driver = {
258 .driver = {
259 .name = "sch_gpio",
260 .owner = THIS_MODULE,
261 },
262 .probe = sch_gpio_probe,
263 .remove = __devexit_p(sch_gpio_remove),
264};
265
266static int __init sch_gpio_init(void)
267{
268 return platform_driver_register(&sch_gpio_driver);
269}
270
271static void __exit sch_gpio_exit(void)
272{
273 platform_driver_unregister(&sch_gpio_driver);
274}
275
276module_init(sch_gpio_init);
277module_exit(sch_gpio_exit);
278
279MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
280MODULE_DESCRIPTION("GPIO interface for Intel Poulsbo SCH");
281MODULE_LICENSE("GPL");
282MODULE_ALIAS("platform:sch_gpio");