2 * sch_gpio.c - GPIO interface for Intel Poulsbo SCH
4 * Copyright (c) 2010 CompuLab Ltd
5 * Author: Denis Turischev <denis@compulab.co.il>
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.
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.
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.
21 #include <linux/init.h>
22 #include <linux/kernel.h>
23 #include <linux/module.h>
25 #include <linux/errno.h>
26 #include <linux/acpi.h>
27 #include <linux/platform_device.h>
29 #include <linux/gpio.h>
31 static DEFINE_SPINLOCK(gpio_lock
);
41 static unsigned short gpio_ba
;
43 static int sch_gpio_core_direction_in(struct gpio_chip
*gc
, unsigned gpio_num
)
46 unsigned short offset
, bit
;
48 spin_lock(&gpio_lock
);
50 offset
= CGIO
+ gpio_num
/ 8;
53 curr_dirs
= inb(gpio_ba
+ offset
);
55 if (!(curr_dirs
& (1 << bit
)))
56 outb(curr_dirs
| (1 << bit
), gpio_ba
+ offset
);
58 spin_unlock(&gpio_lock
);
62 static int sch_gpio_core_get(struct gpio_chip
*gc
, unsigned gpio_num
)
65 unsigned short offset
, bit
;
67 offset
= CGLV
+ gpio_num
/ 8;
70 res
= !!(inb(gpio_ba
+ offset
) & (1 << bit
));
74 static void sch_gpio_core_set(struct gpio_chip
*gc
, unsigned gpio_num
, int val
)
77 unsigned short offset
, bit
;
79 spin_lock(&gpio_lock
);
81 offset
= CGLV
+ gpio_num
/ 8;
84 curr_vals
= inb(gpio_ba
+ offset
);
87 outb(curr_vals
| (1 << bit
), gpio_ba
+ offset
);
89 outb((curr_vals
& ~(1 << bit
)), gpio_ba
+ offset
);
90 spin_unlock(&gpio_lock
);
93 static int sch_gpio_core_direction_out(struct gpio_chip
*gc
,
94 unsigned gpio_num
, int val
)
97 unsigned short offset
, bit
;
99 sch_gpio_core_set(gc
, gpio_num
, val
);
101 spin_lock(&gpio_lock
);
103 offset
= CGIO
+ gpio_num
/ 8;
106 curr_dirs
= inb(gpio_ba
+ offset
);
107 if (curr_dirs
& (1 << bit
))
108 outb(curr_dirs
& ~(1 << bit
), gpio_ba
+ offset
);
110 spin_unlock(&gpio_lock
);
114 static 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
,
123 static int sch_gpio_resume_direction_in(struct gpio_chip
*gc
,
128 spin_lock(&gpio_lock
);
130 curr_dirs
= inb(gpio_ba
+ RGIO
);
132 if (!(curr_dirs
& (1 << gpio_num
)))
133 outb(curr_dirs
| (1 << gpio_num
) , gpio_ba
+ RGIO
);
135 spin_unlock(&gpio_lock
);
139 static int sch_gpio_resume_get(struct gpio_chip
*gc
, unsigned gpio_num
)
141 return !!(inb(gpio_ba
+ RGLV
) & (1 << gpio_num
));
144 static void sch_gpio_resume_set(struct gpio_chip
*gc
,
145 unsigned gpio_num
, int val
)
149 spin_lock(&gpio_lock
);
151 curr_vals
= inb(gpio_ba
+ RGLV
);
154 outb(curr_vals
| (1 << gpio_num
), gpio_ba
+ RGLV
);
156 outb((curr_vals
& ~(1 << gpio_num
)), gpio_ba
+ RGLV
);
158 spin_unlock(&gpio_lock
);
161 static int sch_gpio_resume_direction_out(struct gpio_chip
*gc
,
162 unsigned gpio_num
, int val
)
166 sch_gpio_resume_set(gc
, gpio_num
, val
);
168 spin_lock(&gpio_lock
);
170 curr_dirs
= inb(gpio_ba
+ RGIO
);
171 if (curr_dirs
& (1 << gpio_num
))
172 outb(curr_dirs
& ~(1 << gpio_num
), gpio_ba
+ RGIO
);
174 spin_unlock(&gpio_lock
);
178 static 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
,
187 static int __devinit
sch_gpio_probe(struct platform_device
*pdev
)
189 struct resource
*res
;
192 res
= platform_get_resource(pdev
, IORESOURCE_IO
, 0);
196 if (!request_region(res
->start
, resource_size(res
), pdev
->name
))
199 gpio_ba
= res
->start
;
201 sch_gpio_core
.base
= 0;
202 sch_gpio_core
.ngpio
= 10;
203 sch_gpio_core
.dev
= &pdev
->dev
;
205 sch_gpio_resume
.base
= 10;
206 sch_gpio_resume
.ngpio
= 4;
207 sch_gpio_resume
.dev
= &pdev
->dev
;
209 err
= gpiochip_add(&sch_gpio_core
);
211 goto err_sch_gpio_core
;
213 err
= gpiochip_add(&sch_gpio_resume
);
215 goto err_sch_gpio_resume
;
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
222 outb(0x3, gpio_ba
+ CGEN
+ 1);
224 * SUS_GPIO[2:0] enabled by default
225 * Enable SUS_GPIO3 resume powered gpio explicitly
227 outb(0x8, gpio_ba
+ RGEN
);
232 err
= gpiochip_remove(&sch_gpio_core
);
234 dev_err(&pdev
->dev
, "%s failed, %d\n",
235 "gpiochip_remove()", err
);
238 release_region(res
->start
, resource_size(res
));
244 static int __devexit
sch_gpio_remove(struct platform_device
*pdev
)
246 struct resource
*res
;
250 err
= gpiochip_remove(&sch_gpio_core
);
252 dev_err(&pdev
->dev
, "%s failed, %d\n",
253 "gpiochip_remove()", err
);
254 err
= gpiochip_remove(&sch_gpio_resume
);
256 dev_err(&pdev
->dev
, "%s failed, %d\n",
257 "gpiochip_remove()", err
);
259 res
= platform_get_resource(pdev
, IORESOURCE_IO
, 0);
261 release_region(res
->start
, resource_size(res
));
270 static struct platform_driver sch_gpio_driver
= {
273 .owner
= THIS_MODULE
,
275 .probe
= sch_gpio_probe
,
276 .remove
= __devexit_p(sch_gpio_remove
),
279 static int __init
sch_gpio_init(void)
281 return platform_driver_register(&sch_gpio_driver
);
284 static void __exit
sch_gpio_exit(void)
286 platform_driver_unregister(&sch_gpio_driver
);
289 module_init(sch_gpio_init
);
290 module_exit(sch_gpio_exit
);
292 MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
293 MODULE_DESCRIPTION("GPIO interface for Intel Poulsbo SCH");
294 MODULE_LICENSE("GPL");
295 MODULE_ALIAS("platform:sch_gpio");