Merge branch 'for_linus' of git://git.infradead.org/~dedekind/ubifs-2.6
[pandora-kernel.git] / arch / arm / plat-s3c24xx / gpiolib.c
1 /* linux/arch/arm/plat-s3c24xx/gpiolib.c
2  *
3  * Copyright (c) 2008 Simtec Electronics
4  *      http://armlinux.simtec.co.uk/
5  *      Ben Dooks <ben@simtec.co.uk>
6  *
7  * S3C24XX GPIOlib support
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License.
12 */
13
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/module.h>
17 #include <linux/interrupt.h>
18 #include <linux/ioport.h>
19 #include <linux/io.h>
20 #include <linux/gpio.h>
21
22 #include <asm/hardware.h>
23 #include <asm/irq.h>
24
25 #include <asm/arch/regs-gpio.h>
26
27 struct s3c24xx_gpio_chip {
28         struct gpio_chip        chip;
29         void __iomem            *base;
30 };
31
32 static inline struct s3c24xx_gpio_chip *to_s3c_chip(struct gpio_chip *gpc)
33 {
34         return container_of(gpc, struct s3c24xx_gpio_chip, chip);
35 }
36
37 /* these routines are exported for use by other parts of the platform
38  * and system support, but are not intended to be used directly by the
39  * drivers themsevles.
40  */
41
42 int s3c24xx_gpiolib_input(struct gpio_chip *chip, unsigned offset)
43 {
44         struct s3c24xx_gpio_chip *ourchip = to_s3c_chip(chip);
45         void __iomem *base = ourchip->base;
46         unsigned long flags;
47         unsigned long con;
48
49         local_irq_save(flags);
50
51         con = __raw_readl(base + 0x00);
52         con &= ~(3 << (offset * 2));
53         con |= (S3C2410_GPIO_OUTPUT & 0xf) << (offset * 2);
54
55         __raw_writel(con, base + 0x00);
56
57         local_irq_restore(flags);
58         return 0;
59 }
60
61 int s3c24xx_gpiolib_output(struct gpio_chip *chip,
62                                   unsigned offset, int value)
63 {
64         struct s3c24xx_gpio_chip *ourchip = to_s3c_chip(chip);
65         void __iomem *base = ourchip->base;
66         unsigned long flags;
67         unsigned long dat;
68         unsigned long con;
69
70         local_irq_save(flags);
71
72         dat = __raw_readl(base + 0x04);
73         dat &= ~(1 << offset);
74         if (value)
75                 dat |= 1 << offset;
76         __raw_writel(dat, base + 0x04);
77
78         con = __raw_readl(base + 0x00);
79         con &= ~(3 << (offset * 2));
80         con |= (S3C2410_GPIO_OUTPUT & 0xf) << (offset * 2);
81
82         __raw_writel(con, base + 0x00);
83         __raw_writel(dat, base + 0x04);
84
85         local_irq_restore(flags);
86         return 0;
87 }
88
89 void s3c24xx_gpiolib_set(struct gpio_chip *chip, unsigned offset, int value)
90 {
91         struct s3c24xx_gpio_chip *ourchip = to_s3c_chip(chip);
92         void __iomem *base = ourchip->base;
93         unsigned long flags;
94         unsigned long dat;
95
96         local_irq_save(flags);
97
98         dat = __raw_readl(base + 0x04);
99         dat &= ~(1 << offset);
100         if (value)
101                 dat |= 1 << offset;
102         __raw_writel(dat, base + 0x04);
103
104         local_irq_restore(flags);
105 }
106
107 int s3c24xx_gpiolib_get(struct gpio_chip *chip, unsigned offset)
108 {
109         struct s3c24xx_gpio_chip *ourchip = to_s3c_chip(chip);
110         unsigned long val;
111
112         val = __raw_readl(ourchip->base + 0x04);
113         val >>= offset;
114         val &= 1;
115
116         return val;
117 }
118
119 static int s3c24xx_gpiolib_banka_input(struct gpio_chip *chip, unsigned offset)
120 {
121         return -EINVAL;
122 }
123
124 static int s3c24xx_gpiolib_banka_output(struct gpio_chip *chip,
125                                         unsigned offset, int value)
126 {
127         struct s3c24xx_gpio_chip *ourchip = to_s3c_chip(chip);
128         void __iomem *base = ourchip->base;
129         unsigned long flags;
130         unsigned long dat;
131         unsigned long con;
132
133         local_irq_save(flags);
134
135         con = __raw_readl(base + 0x00);
136         dat = __raw_readl(base + 0x04);
137
138         dat &= ~(1 << offset);
139         if (value)
140                 dat |= 1 << offset;
141
142         __raw_writel(dat, base + 0x04);
143
144         con &= ~(1 << offset);
145
146         __raw_writel(con, base + 0x00);
147         __raw_writel(dat, base + 0x04);
148
149         local_irq_restore(flags);
150         return 0;
151 }
152
153
154 struct s3c24xx_gpio_chip gpios[] = {
155         [0] = {
156                 .base   = S3C24XX_GPIO_BASE(S3C2410_GPA0),
157                 .chip   = {
158                         .base                   = S3C2410_GPA0,
159                         .owner                  = THIS_MODULE,
160                         .label                  = "GPIOA",
161                         .ngpio                  = 24,
162                         .direction_input        = s3c24xx_gpiolib_banka_input,
163                         .direction_output       = s3c24xx_gpiolib_banka_output,
164                         .set                    = s3c24xx_gpiolib_set,
165                         .get                    = s3c24xx_gpiolib_get,
166                 },
167         },
168         [1] = {
169                 .base   = S3C24XX_GPIO_BASE(S3C2410_GPB0),
170                 .chip   = {
171                         .base                   = S3C2410_GPB0,
172                         .owner                  = THIS_MODULE,
173                         .label                  = "GPIOB",
174                         .ngpio                  = 16,
175                         .direction_input        = s3c24xx_gpiolib_input,
176                         .direction_output       = s3c24xx_gpiolib_output,
177                         .set                    = s3c24xx_gpiolib_set,
178                         .get                    = s3c24xx_gpiolib_get,
179                 },
180         },
181         [2] = {
182                 .base   = S3C24XX_GPIO_BASE(S3C2410_GPC0),
183                 .chip   = {
184                         .base                   = S3C2410_GPC0,
185                         .owner                  = THIS_MODULE,
186                         .label                  = "GPIOC",
187                         .ngpio                  = 16,
188                         .direction_input        = s3c24xx_gpiolib_input,
189                         .direction_output       = s3c24xx_gpiolib_output,
190                         .set                    = s3c24xx_gpiolib_set,
191                         .get                    = s3c24xx_gpiolib_get,
192                 },
193         },
194         [3] = {
195                 .base   = S3C24XX_GPIO_BASE(S3C2410_GPD0),
196                 .chip   = {
197                         .base                   = S3C2410_GPD0,
198                         .owner                  = THIS_MODULE,
199                         .label                  = "GPIOD",
200                         .ngpio                  = 16,
201                         .direction_input        = s3c24xx_gpiolib_input,
202                         .direction_output       = s3c24xx_gpiolib_output,
203                         .set                    = s3c24xx_gpiolib_set,
204                         .get                    = s3c24xx_gpiolib_get,
205                 },
206         },
207         [4] = {
208                 .base   = S3C24XX_GPIO_BASE(S3C2410_GPE0),
209                 .chip   = {
210                         .base                   = S3C2410_GPE0,
211                         .label                  = "GPIOE",
212                         .owner                  = THIS_MODULE,
213                         .ngpio                  = 16,
214                         .direction_input        = s3c24xx_gpiolib_input,
215                         .direction_output       = s3c24xx_gpiolib_output,
216                         .set                    = s3c24xx_gpiolib_set,
217                         .get                    = s3c24xx_gpiolib_get,
218                 },
219         },
220         [5] = {
221                 .base   = S3C24XX_GPIO_BASE(S3C2410_GPF0),
222                 .chip   = {
223                         .base                   = S3C2410_GPF0,
224                         .owner                  = THIS_MODULE,
225                         .label                  = "GPIOF",
226                         .ngpio                  = 8,
227                         .direction_input        = s3c24xx_gpiolib_input,
228                         .direction_output       = s3c24xx_gpiolib_output,
229                         .set                    = s3c24xx_gpiolib_set,
230                         .get                    = s3c24xx_gpiolib_get,
231                 },
232         },
233         [6] = {
234                 .base   = S3C24XX_GPIO_BASE(S3C2410_GPG0),
235                 .chip   = {
236                         .base                   = S3C2410_GPG0,
237                         .owner                  = THIS_MODULE,
238                         .label                  = "GPIOG",
239                         .ngpio                  = 10,
240                         .direction_input        = s3c24xx_gpiolib_input,
241                         .direction_output       = s3c24xx_gpiolib_output,
242                         .set                    = s3c24xx_gpiolib_set,
243                         .get                    = s3c24xx_gpiolib_get,
244                 },
245         },
246 };
247
248 static __init int s3c24xx_gpiolib_init(void)
249 {
250         struct s3c24xx_gpio_chip *chip = gpios;
251         int gpn;
252
253         for (gpn = 0; gpn < ARRAY_SIZE(gpios); gpn++, chip++)
254                 gpiochip_add(&chip->chip);
255
256         return 0;
257 }
258
259 arch_initcall(s3c24xx_gpiolib_init);