Linux-2.6.12-rc2
[linux-3.10.git] / arch / arm / mach-s3c2410 / gpio.c
1 /* linux/arch/arm/mach-s3c2410/gpio.c
2  *
3  * Copyright (c) 2004-2005 Simtec Electronics
4  *      Ben Dooks <ben@simtec.co.uk>
5  *
6  * S3C2410 GPIO support
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  * Changelog
23  *      13-Sep-2004  BJD  Implemented change of MISCCR
24  *      14-Sep-2004  BJD  Added getpin call
25  *      14-Sep-2004  BJD  Fixed bug in setpin() call
26  *      30-Sep-2004  BJD  Fixed cfgpin() mask bug
27  *      01-Oct-2004  BJD  Added getcfg() to get pin configuration
28  *      01-Oct-2004  BJD  Fixed mask bug in pullup() call
29  *      01-Oct-2004  BJD  Added getirq() to turn pin into irqno
30  *      04-Oct-2004  BJD  Added irq filter controls for GPIO
31  *      05-Nov-2004  BJD  EXPORT_SYMBOL() added for all code
32  *      13-Mar-2005  BJD  Updates for __iomem
33  */
34
35
36 #include <linux/kernel.h>
37 #include <linux/init.h>
38 #include <linux/module.h>
39 #include <linux/interrupt.h>
40 #include <linux/ioport.h>
41
42 #include <asm/hardware.h>
43 #include <asm/irq.h>
44 #include <asm/io.h>
45
46 #include <asm/arch/regs-gpio.h>
47
48 void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
49 {
50         void __iomem *base = S3C2410_GPIO_BASE(pin);
51         unsigned long mask;
52         unsigned long con;
53         unsigned long flags;
54
55         if (pin < S3C2410_GPIO_BANKB) {
56                 mask = 1 << S3C2410_GPIO_OFFSET(pin);
57         } else {
58                 mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;
59         }
60
61         local_irq_save(flags);
62
63         con  = __raw_readl(base + 0x00);
64         con &= ~mask;
65         con |= function;
66
67         __raw_writel(con, base + 0x00);
68
69         local_irq_restore(flags);
70 }
71
72 EXPORT_SYMBOL(s3c2410_gpio_cfgpin);
73
74 unsigned int s3c2410_gpio_getcfg(unsigned int pin)
75 {
76         void __iomem *base = S3C2410_GPIO_BASE(pin);
77         unsigned long mask;
78
79         if (pin < S3C2410_GPIO_BANKB) {
80                 mask = 1 << S3C2410_GPIO_OFFSET(pin);
81         } else {
82                 mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;
83         }
84
85         return __raw_readl(base) & mask;
86 }
87
88 EXPORT_SYMBOL(s3c2410_gpio_getcfg);
89
90 void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
91 {
92         void __iomem *base = S3C2410_GPIO_BASE(pin);
93         unsigned long offs = S3C2410_GPIO_OFFSET(pin);
94         unsigned long flags;
95         unsigned long up;
96
97         if (pin < S3C2410_GPIO_BANKB)
98                 return;
99
100         local_irq_save(flags);
101
102         up = __raw_readl(base + 0x08);
103         up &= ~(1L << offs);
104         up |= to << offs;
105         __raw_writel(up, base + 0x08);
106
107         local_irq_restore(flags);
108 }
109
110 EXPORT_SYMBOL(s3c2410_gpio_pullup);
111
112 void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
113 {
114         void __iomem *base = S3C2410_GPIO_BASE(pin);
115         unsigned long offs = S3C2410_GPIO_OFFSET(pin);
116         unsigned long flags;
117         unsigned long dat;
118
119         local_irq_save(flags);
120
121         dat = __raw_readl(base + 0x04);
122         dat &= ~(1 << offs);
123         dat |= to << offs;
124         __raw_writel(dat, base + 0x04);
125
126         local_irq_restore(flags);
127 }
128
129 EXPORT_SYMBOL(s3c2410_gpio_setpin);
130
131 unsigned int s3c2410_gpio_getpin(unsigned int pin)
132 {
133         void __iomem *base = S3C2410_GPIO_BASE(pin);
134         unsigned long offs = S3C2410_GPIO_OFFSET(pin);
135
136         return __raw_readl(base + 0x04) & (1<< offs);
137 }
138
139 EXPORT_SYMBOL(s3c2410_gpio_getpin);
140
141 unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
142 {
143         unsigned long flags;
144         unsigned long misccr;
145
146         local_irq_save(flags);
147         misccr = __raw_readl(S3C2410_MISCCR);
148         misccr &= ~clear;
149         misccr ^= change;
150         __raw_writel(misccr, S3C2410_MISCCR);
151         local_irq_restore(flags);
152
153         return misccr;
154 }
155
156 EXPORT_SYMBOL(s3c2410_modify_misccr);
157
158 int s3c2410_gpio_getirq(unsigned int pin)
159 {
160         if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15_EINT23)
161                 return -1;      /* not valid interrupts */
162
163         if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
164                 return -1;      /* not valid pin */
165
166         if (pin < S3C2410_GPF4)
167                 return (pin - S3C2410_GPF0) + IRQ_EINT0;
168
169         if (pin < S3C2410_GPG0)
170                 return (pin - S3C2410_GPF4) + IRQ_EINT4;
171
172         return (pin - S3C2410_GPG0) + IRQ_EINT8;
173 }
174
175 EXPORT_SYMBOL(s3c2410_gpio_getirq);
176
177 int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
178                            unsigned int config)
179 {
180         void __iomem *reg = S3C2410_EINFLT0;
181         unsigned long flags;
182         unsigned long val;
183
184         if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15)
185                 return -1;
186
187         config &= 0xff;
188
189         pin -= S3C2410_GPG8_EINT16;
190         reg += pin & ~3;
191
192         local_irq_save(flags);
193
194         /* update filter width and clock source */
195
196         val = __raw_readl(reg);
197         val &= ~(0xff << ((pin & 3) * 8));
198         val |= config << ((pin & 3) * 8);
199         __raw_writel(val, reg);
200
201         /* update filter enable */
202
203         val = __raw_readl(S3C2410_EXTINT2);
204         val &= ~(1 << ((pin * 4) + 3));
205         val |= on << ((pin * 4) + 3);
206         __raw_writel(val, S3C2410_EXTINT2);
207
208         local_irq_restore(flags);
209
210         return 0;
211 }
212
213 EXPORT_SYMBOL(s3c2410_gpio_irqfilter);