Merge git://git.infradead.org/battery-2.6
[pandora-kernel.git] / arch / arm / plat-s3c64xx / gpiolib.c
1 /* arch/arm/plat-s3c64xx/gpiolib.c
2  *
3  * Copyright 2008 Openmoko, Inc.
4  * Copyright 2008 Simtec Electronics
5  *      Ben Dooks <ben@simtec.co.uk>
6  *      http://armlinux.simtec.co.uk/
7  *
8  * S3C64XX - GPIOlib support 
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  */
14
15 #include <linux/kernel.h>
16 #include <linux/irq.h>
17 #include <linux/io.h>
18
19 #include <mach/map.h>
20 #include <mach/gpio.h>
21 #include <mach/gpio-core.h>
22
23 #include <plat/gpio-cfg.h>
24 #include <plat/gpio-cfg-helpers.h>
25 #include <plat/regs-gpio.h>
26
27 /* GPIO bank summary:
28  *
29  * Bank GPIOs   Style   SlpCon  ExtInt Group
30  * A    8       4Bit    Yes     1
31  * B    7       4Bit    Yes     1
32  * C    8       4Bit    Yes     2
33  * D    5       4Bit    Yes     3
34  * E    5       4Bit    Yes     None
35  * F    16      2Bit    Yes     4 [1]
36  * G    7       4Bit    Yes     5
37  * H    10      4Bit[2] Yes     6
38  * I    16      2Bit    Yes     None
39  * J    12      2Bit    Yes     None
40  * K    16      4Bit[2] No      None
41  * L    15      4Bit[2] No      None
42  * M    6       4Bit    No      IRQ_EINT
43  * N    16      2Bit    No      IRQ_EINT
44  * O    16      2Bit    Yes     7
45  * P    15      2Bit    Yes     8
46  * Q    9       2Bit    Yes     9
47  *
48  * [1] BANKF pins 14,15 do not form part of the external interrupt sources
49  * [2] BANK has two control registers, GPxCON0 and GPxCON1
50  */
51
52 #define OFF_GPCON       (0x00)
53 #define OFF_GPDAT       (0x04)
54
55 #define con_4bit_shift(__off) ((__off) * 4)
56
57 #if 1
58 #define gpio_dbg(x...) do { } while(0)
59 #else
60 #define gpio_dbg(x...) printk(KERN_DEBUG x)
61 #endif
62
63 /* The s3c64xx_gpiolib_4bit routines are to control the gpio banks where
64  * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the
65  * following example:
66  *
67  * base + 0x00: Control register, 4 bits per gpio
68  *              gpio n: 4 bits starting at (4*n)
69  *              0000 = input, 0001 = output, others mean special-function
70  * base + 0x04: Data register, 1 bit per gpio
71  *              bit n: data bit n
72  *
73  * Note, since the data register is one bit per gpio and is at base + 0x4
74  * we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of
75  * the output.
76 */
77
78 static int s3c64xx_gpiolib_4bit_input(struct gpio_chip *chip, unsigned offset)
79 {
80         struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
81         void __iomem *base = ourchip->base;
82         unsigned long con;
83
84         con = __raw_readl(base + OFF_GPCON);
85         con &= ~(0xf << con_4bit_shift(offset));
86         __raw_writel(con, base + OFF_GPCON);
87
88         gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con);
89
90         return 0;
91 }
92
93 static int s3c64xx_gpiolib_4bit_output(struct gpio_chip *chip,
94                                        unsigned offset, int value)
95 {
96         struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
97         void __iomem *base = ourchip->base;
98         unsigned long con;
99         unsigned long dat;
100
101         con = __raw_readl(base + OFF_GPCON);
102         con &= ~(0xf << con_4bit_shift(offset));
103         con |= 0x1 << con_4bit_shift(offset);
104
105         dat = __raw_readl(base + OFF_GPDAT);
106         if (value)
107                 dat |= 1 << offset;
108         else
109                 dat &= ~(1 << offset);
110
111         __raw_writel(dat, base + OFF_GPDAT);
112         __raw_writel(con, base + OFF_GPCON);
113         __raw_writel(dat, base + OFF_GPDAT);
114
115         gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
116
117         return 0;
118 }
119
120 /* The next set of routines are for the case where the GPIO configuration
121  * registers are 4 bits per GPIO but there is more than one register (the
122  * bank has more than 8 GPIOs.
123  *
124  * This case is the similar to the 4 bit case, but the registers are as
125  * follows:
126  *
127  * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs)
128  *              gpio n: 4 bits starting at (4*n)
129  *              0000 = input, 0001 = output, others mean special-function
130  * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs)
131  *              gpio n: 4 bits starting at (4*n)
132  *              0000 = input, 0001 = output, others mean special-function
133  * base + 0x08: Data register, 1 bit per gpio
134  *              bit n: data bit n
135  *
136  * To allow us to use the s3c_gpiolib_get and s3c_gpiolib_set routines we
137  * store the 'base + 0x4' address so that these routines see the data
138  * register at ourchip->base + 0x04.
139 */
140
141 static int s3c64xx_gpiolib_4bit2_input(struct gpio_chip *chip, unsigned offset)
142 {
143         struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
144         void __iomem *base = ourchip->base;
145         void __iomem *regcon = base;
146         unsigned long con;
147
148         if (offset > 7)
149                 offset -= 8;
150         else
151                 regcon -= 4;
152
153         con = __raw_readl(regcon);
154         con &= ~(0xf << con_4bit_shift(offset));
155         __raw_writel(con, regcon);
156
157         gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con);
158
159         return 0;
160
161 }
162
163 static int s3c64xx_gpiolib_4bit2_output(struct gpio_chip *chip,
164                                        unsigned offset, int value)
165 {
166         struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
167         void __iomem *base = ourchip->base;
168         void __iomem *regcon = base;
169         unsigned long con;
170         unsigned long dat;
171
172         if (offset > 7)
173                 offset -= 8;
174         else
175                 regcon -= 4;
176
177         con = __raw_readl(regcon);
178         con &= ~(0xf << con_4bit_shift(offset));
179         con |= 0x1 << con_4bit_shift(offset);
180
181         dat = __raw_readl(base + OFF_GPDAT);
182         if (value)
183                 dat |= 1 << offset;
184         else
185                 dat &= ~(1 << offset);
186
187         __raw_writel(dat, base + OFF_GPDAT);
188         __raw_writel(con, regcon);
189         __raw_writel(dat, base + OFF_GPDAT);
190
191         gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
192
193         return 0;
194 }
195
196 static struct s3c_gpio_cfg gpio_4bit_cfg_noint = {
197         .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
198         .set_pull       = s3c_gpio_setpull_updown,
199         .get_pull       = s3c_gpio_getpull_updown,
200 };
201
202 static struct s3c_gpio_cfg gpio_4bit_cfg_eint0111 = {
203         .cfg_eint       = 7,
204         .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
205         .set_pull       = s3c_gpio_setpull_updown,
206         .get_pull       = s3c_gpio_getpull_updown,
207 };
208
209 static struct s3c_gpio_cfg gpio_4bit_cfg_eint0011 = {
210         .cfg_eint       = 3,
211         .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
212         .set_pull       = s3c_gpio_setpull_updown,
213         .get_pull       = s3c_gpio_getpull_updown,
214 };
215
216 static struct s3c_gpio_chip gpio_4bit[] = {
217         {
218                 .base   = S3C64XX_GPA_BASE,
219                 .config = &gpio_4bit_cfg_eint0111,
220                 .chip   = {
221                         .base   = S3C64XX_GPA(0),
222                         .ngpio  = S3C64XX_GPIO_A_NR,
223                         .label  = "GPA",
224                 },
225         }, {
226                 .base   = S3C64XX_GPB_BASE,
227                 .config = &gpio_4bit_cfg_eint0111,
228                 .chip   = {
229                         .base   = S3C64XX_GPB(0),
230                         .ngpio  = S3C64XX_GPIO_B_NR,
231                         .label  = "GPB",
232                 },
233         }, {
234                 .base   = S3C64XX_GPC_BASE,
235                 .config = &gpio_4bit_cfg_eint0111,
236                 .chip   = {
237                         .base   = S3C64XX_GPC(0),
238                         .ngpio  = S3C64XX_GPIO_C_NR,
239                         .label  = "GPC",
240                 },
241         }, {
242                 .base   = S3C64XX_GPD_BASE,
243                 .config = &gpio_4bit_cfg_eint0111,
244                 .chip   = {
245                         .base   = S3C64XX_GPD(0),
246                         .ngpio  = S3C64XX_GPIO_D_NR,
247                         .label  = "GPD",
248                 },
249         }, {
250                 .base   = S3C64XX_GPE_BASE,
251                 .config = &gpio_4bit_cfg_noint,
252                 .chip   = {
253                         .base   = S3C64XX_GPE(0),
254                         .ngpio  = S3C64XX_GPIO_E_NR,
255                         .label  = "GPE",
256                 },
257         }, {
258                 .base   = S3C64XX_GPG_BASE,
259                 .config = &gpio_4bit_cfg_eint0111,
260                 .chip   = {
261                         .base   = S3C64XX_GPG(0),
262                         .ngpio  = S3C64XX_GPIO_G_NR,
263                         .label  = "GPG",
264                 },
265         }, {
266                 .base   = S3C64XX_GPM_BASE,
267                 .config = &gpio_4bit_cfg_eint0011,
268                 .chip   = {
269                         .base   = S3C64XX_GPM(0),
270                         .ngpio  = S3C64XX_GPIO_M_NR,
271                         .label  = "GPM",
272                 },
273         },
274 };
275
276 static struct s3c_gpio_chip gpio_4bit2[] = {
277         {
278                 .base   = S3C64XX_GPH_BASE + 0x4,
279                 .config = &gpio_4bit_cfg_eint0111,
280                 .chip   = {
281                         .base   = S3C64XX_GPH(0),
282                         .ngpio  = S3C64XX_GPIO_H_NR,
283                         .label  = "GPH",
284                 },
285         }, {
286                 .base   = S3C64XX_GPK_BASE + 0x4,
287                 .config = &gpio_4bit_cfg_noint,
288                 .chip   = {
289                         .base   = S3C64XX_GPK(0),
290                         .ngpio  = S3C64XX_GPIO_K_NR,
291                         .label  = "GPK",
292                 },
293         }, {
294                 .base   = S3C64XX_GPL_BASE + 0x4,
295                 .config = &gpio_4bit_cfg_eint0011,
296                 .chip   = {
297                         .base   = S3C64XX_GPL(0),
298                         .ngpio  = S3C64XX_GPIO_L_NR,
299                         .label  = "GPL",
300                 },
301         },
302 };
303
304 static struct s3c_gpio_cfg gpio_2bit_cfg_noint = {
305         .set_config     = s3c_gpio_setcfg_s3c24xx,
306         .set_pull       = s3c_gpio_setpull_updown,
307         .get_pull       = s3c_gpio_getpull_updown,
308 };
309
310 static struct s3c_gpio_cfg gpio_2bit_cfg_eint10 = {
311         .cfg_eint       = 2,
312         .set_config     = s3c_gpio_setcfg_s3c24xx,
313         .set_pull       = s3c_gpio_setpull_updown,
314         .get_pull       = s3c_gpio_getpull_updown,
315 };
316
317 static struct s3c_gpio_cfg gpio_2bit_cfg_eint11 = {
318         .cfg_eint       = 3,
319         .set_config     = s3c_gpio_setcfg_s3c24xx,
320         .set_pull       = s3c_gpio_setpull_updown,
321         .get_pull       = s3c_gpio_getpull_updown,
322 };
323
324 int s3c64xx_gpio2int_gpn(struct gpio_chip *chip, unsigned pin)
325 {
326         return IRQ_EINT(0) + pin;
327 }
328
329 static struct s3c_gpio_chip gpio_2bit[] = {
330         {
331                 .base   = S3C64XX_GPF_BASE,
332                 .config = &gpio_2bit_cfg_eint11,
333                 .chip   = {
334                         .base   = S3C64XX_GPF(0),
335                         .ngpio  = S3C64XX_GPIO_F_NR,
336                         .label  = "GPF",
337                 },
338         }, {
339                 .base   = S3C64XX_GPI_BASE,
340                 .config = &gpio_2bit_cfg_noint,
341                 .chip   = {
342                         .base   = S3C64XX_GPI(0),
343                         .ngpio  = S3C64XX_GPIO_I_NR,
344                         .label  = "GPI",
345                 },
346         }, {
347                 .base   = S3C64XX_GPJ_BASE,
348                 .config = &gpio_2bit_cfg_noint,
349                 .chip   = {
350                         .base   = S3C64XX_GPJ(0),
351                         .ngpio  = S3C64XX_GPIO_J_NR,
352                         .label  = "GPJ",
353                 },
354         }, {
355                 .base   = S3C64XX_GPN_BASE,
356                 .config = &gpio_2bit_cfg_eint10,
357                 .chip   = {
358                         .base   = S3C64XX_GPN(0),
359                         .ngpio  = S3C64XX_GPIO_N_NR,
360                         .label  = "GPN",
361                         .to_irq = s3c64xx_gpio2int_gpn,
362                 },
363         }, {
364                 .base   = S3C64XX_GPO_BASE,
365                 .config = &gpio_2bit_cfg_eint11,
366                 .chip   = {
367                         .base   = S3C64XX_GPO(0),
368                         .ngpio  = S3C64XX_GPIO_O_NR,
369                         .label  = "GPO",
370                 },
371         }, {
372                 .base   = S3C64XX_GPP_BASE,
373                 .config = &gpio_2bit_cfg_eint11,
374                 .chip   = {
375                         .base   = S3C64XX_GPP(0),
376                         .ngpio  = S3C64XX_GPIO_P_NR,
377                         .label  = "GPP",
378                 },
379         }, {
380                 .base   = S3C64XX_GPQ_BASE,
381                 .config = &gpio_2bit_cfg_eint11,
382                 .chip   = {
383                         .base   = S3C64XX_GPQ(0),
384                         .ngpio  = S3C64XX_GPIO_Q_NR,
385                         .label  = "GPQ",
386                 },
387         },
388 };
389
390 static __init void s3c64xx_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
391 {
392         chip->chip.direction_input = s3c64xx_gpiolib_4bit_input;
393         chip->chip.direction_output = s3c64xx_gpiolib_4bit_output;
394         chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
395 }
396
397 static __init void s3c64xx_gpiolib_add_4bit2(struct s3c_gpio_chip *chip)
398 {
399         chip->chip.direction_input = s3c64xx_gpiolib_4bit2_input;
400         chip->chip.direction_output = s3c64xx_gpiolib_4bit2_output;
401         chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
402 }
403
404 static __init void s3c64xx_gpiolib_add_2bit(struct s3c_gpio_chip *chip)
405 {
406         chip->pm = __gpio_pm(&s3c_gpio_pm_2bit);
407 }
408
409 static __init void s3c64xx_gpiolib_add(struct s3c_gpio_chip *chips,
410                                        int nr_chips,
411                                        void (*fn)(struct s3c_gpio_chip *))
412 {
413         for (; nr_chips > 0; nr_chips--, chips++) {
414                 if (fn)
415                         (fn)(chips);
416                 s3c_gpiolib_add(chips);
417         }
418 }
419
420 static __init int s3c64xx_gpiolib_init(void)
421 {
422         s3c64xx_gpiolib_add(gpio_4bit, ARRAY_SIZE(gpio_4bit),
423                             s3c64xx_gpiolib_add_4bit);
424
425         s3c64xx_gpiolib_add(gpio_4bit2, ARRAY_SIZE(gpio_4bit2),
426                             s3c64xx_gpiolib_add_4bit2);
427
428         s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit),
429                             s3c64xx_gpiolib_add_2bit);
430
431         return 0;
432 }
433
434 core_initcall(s3c64xx_gpiolib_init);