]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/plat-s3c64xx/gpiolib.c
[ARM] S3C64XX: GPIO library support
[linux-2.6-omap-h63xx.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
22 #include <plat/gpio-core.h>
23 #include <plat/regs-gpio.h>
24
25 /* GPIO bank summary:
26  *
27  * Bank GPIOs   Style   SlpCon  ExtInt Group
28  * A    8       4Bit    Yes     1
29  * B    7       4Bit    Yes     1
30  * C    8       4Bit    Yes     2
31  * D    5       4Bit    Yes     3
32  * E    5       4Bit    Yes     None
33  * F    16      2Bit    Yes     4 [1]
34  * G    7       4Bit    Yes     5
35  * H    10      4Bit[2] Yes     6
36  * I    16      2Bit    Yes     None
37  * J    12      2Bit    Yes     None
38  * K    16      4Bit[2] No      None
39  * L    15      4Bit[2] No      None
40  * M    6       4Bit    No      IRQ_EINT
41  * N    16      2Bit    No      IRQ_EINT
42  * O    16      2Bit    Yes     7
43  * P    15      2Bit    Yes     8
44  * Q    9       2Bit    Yes     9
45  *
46  * [1] BANKF pins 14,15 do not form part of the external interrupt sources
47  * [2] BANK has two control registers, GPxCON0 and GPxCON1
48  */
49
50 #define OFF_GPCON       (0x00)
51 #define OFF_GPDAT       (0x04)
52
53 #define con_4bit_shift(__off) ((__off) * 4)
54
55 /* The s3c64xx_gpiolib_4bit routines are to control the gpio banks where
56  * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the
57  * following example:
58  *
59  * base + 0x00: Control register, 4 bits per gpio
60  *              gpio n: 4 bits starting at (4*n)
61  *              0000 = input, 0001 = output, others mean special-function
62  * base + 0x04: Data register, 1 bit per gpio
63  *              bit n: data bit n
64  *
65  * Note, since the data register is one bit per gpio and is at base + 0x4
66  * we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of
67  * the output.
68 */
69
70 static int s3c64xx_gpiolib_4bit_input(struct gpio_chip *chip, unsigned offset)
71 {
72         struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
73         void __iomem *base = ourchip->base;
74         unsigned long con;
75
76         con = __raw_readl(base + OFF_GPCON);
77         con &= ~(0xf << con_4bit_shift(offset));
78         __raw_writel(con, base + OFF_GPCON);
79
80         return 0;
81 }
82
83 static int s3c64xx_gpiolib_4bit_output(struct gpio_chip *chip,
84                                        unsigned offset, int value)
85 {
86         struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
87         void __iomem *base = ourchip->base;
88         unsigned long con;
89         unsigned long dat;
90
91         con = __raw_readl(base + OFF_GPCON);
92         con &= ~(0xf << con_4bit_shift(offset));
93         con |= 0x1 << con_4bit_shift(offset);
94
95         dat = __raw_readl(base + OFF_GPDAT);
96         if (value)
97                 dat |= 1 << offset;
98         else
99                 dat &= ~(1 << offset);
100
101         __raw_writel(dat, base + OFF_GPDAT);
102         __raw_writel(con, base + OFF_GPCON);
103         __raw_writel(dat, base + OFF_GPDAT);
104
105         return 0;
106 }
107
108 /* The next set of routines are for the case where the GPIO configuration
109  * registers are 4 bits per GPIO but there is more than one register (the
110  * bank has more than 8 GPIOs.
111  *
112  * This case is the similar to the 4 bit case, but the registers are as
113  * follows:
114  *
115  * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs)
116  *              gpio n: 4 bits starting at (4*n)
117  *              0000 = input, 0001 = output, others mean special-function
118  * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs)
119  *              gpio n: 4 bits starting at (4*n)
120  *              0000 = input, 0001 = output, others mean special-function
121  * base + 0x08: Data register, 1 bit per gpio
122  *              bit n: data bit n
123  *
124  * To allow us to use the s3c_gpiolib_get and s3c_gpiolib_set routines we
125  * store the 'base + 0x4' address so that these routines see the data
126  * register at ourchip->base + 0x04.
127 */
128
129 static int s3c64xx_gpiolib_4bit2_input(struct gpio_chip *chip, unsigned offset)
130 {
131         struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
132         void __iomem *base = ourchip->base;
133         void __iomem *regcon = base;
134         unsigned long con;
135
136         if (offset > 7)
137                 offset -= 8;
138         else
139                 regcon -= 4;
140
141         con = __raw_readl(regcon);
142         con &= ~(0xf << con_4bit_shift(offset));
143         __raw_writel(con, regcon);
144
145         return 0;
146
147 }
148
149 static int s3c64xx_gpiolib_4bit2_output(struct gpio_chip *chip,
150                                        unsigned offset, int value)
151 {
152         struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
153         void __iomem *base = ourchip->base;
154         void __iomem *regcon = base;
155         unsigned long con;
156         unsigned long dat;
157
158         if (offset > 7)
159                 offset -= 8;
160         else
161                 regcon -= 4;
162
163         con = __raw_readl(regcon);
164         con &= ~(0xf << con_4bit_shift(offset));
165         con |= 0x1 << con_4bit_shift(offset);
166
167         dat = __raw_readl(base + OFF_GPDAT);
168         if (value)
169                 dat |= 1 << offset;
170         else
171                 dat &= ~(1 << offset);
172
173         __raw_writel(dat, base + OFF_GPDAT);
174         __raw_writel(con, regcon);
175         __raw_writel(dat, base + OFF_GPDAT);
176
177         return 0;
178 }
179
180 static struct s3c_gpio_chip gpio_4bit[] = {
181         {
182                 .base   = S3C64XX_GPA_BASE,
183                 .chip   = {
184                         .base   = S3C64XX_GPA(0),
185                         .ngpio  = S3C64XX_GPIO_A_NR,
186                         .label  = "GPA",
187                 },
188         }, {
189                 .base   = S3C64XX_GPB_BASE,
190                 .chip   = {
191                         .base   = S3C64XX_GPB(0),
192                         .ngpio  = S3C64XX_GPIO_B_NR,
193                         .label  = "GPB",
194                 },
195         }, {
196                 .base   = S3C64XX_GPC_BASE,
197                 .chip   = {
198                         .base   = S3C64XX_GPC(0),
199                         .ngpio  = S3C64XX_GPIO_C_NR,
200                         .label  = "GPC",
201                 },
202         }, {
203                 .base   = S3C64XX_GPD_BASE,
204                 .chip   = {
205                         .base   = S3C64XX_GPD(0),
206                         .ngpio  = S3C64XX_GPIO_D_NR,
207                         .label  = "GPD",
208                 },
209         }, {
210                 .base   = S3C64XX_GPE_BASE,
211                 .chip   = {
212                         .base   = S3C64XX_GPE(0),
213                         .ngpio  = S3C64XX_GPIO_E_NR,
214                         .label  = "GPE",
215                 },
216         }, {
217                 .base   = S3C64XX_GPG_BASE,
218                 .chip   = {
219                         .base   = S3C64XX_GPG(0),
220                         .ngpio  = S3C64XX_GPIO_G_NR,
221                         .label  = "GPG",
222                 },
223         }, {
224                 .base   = S3C64XX_GPM_BASE,
225                 .chip   = {
226                         .base   = S3C64XX_GPM(0),
227                         .ngpio  = S3C64XX_GPIO_M_NR,
228                         .label  = "GPM",
229                 },
230         },
231 };
232
233 static struct s3c_gpio_chip gpio_4bit2[] = {
234         {
235                 .base   = S3C64XX_GPH_BASE + 0x4,
236                 .chip   = {
237                         .base   = S3C64XX_GPH(0),
238                         .ngpio  = S3C64XX_GPIO_H_NR,
239                         .label  = "GPH",
240                 },
241         }, {
242                 .base   = S3C64XX_GPK_BASE + 0x4,
243                 .chip   = {
244                         .base   = S3C64XX_GPK(0),
245                         .ngpio  = S3C64XX_GPIO_K_NR,
246                         .label  = "GPK",
247                 },
248         }, {
249                 .base   = S3C64XX_GPL_BASE + 0x4,
250                 .chip   = {
251                         .base   = S3C64XX_GPL(0),
252                         .ngpio  = S3C64XX_GPIO_L_NR,
253                         .label  = "GPL",
254                 },
255         },
256 };
257
258 static struct s3c_gpio_chip gpio_2bit[] = {
259         {
260                 .base   = S3C64XX_GPF_BASE,
261                 .chip   = {
262                         .base   = S3C64XX_GPF(0),
263                         .ngpio  = S3C64XX_GPIO_F_NR,
264                         .label  = "GPF",
265                 },
266         }, {
267                 .base   = S3C64XX_GPI_BASE,
268                 .chip   = {
269                         .base   = S3C64XX_GPI(0),
270                         .ngpio  = S3C64XX_GPIO_I_NR,
271                         .label  = "GPI",
272                 },
273         }, {
274                 .base   = S3C64XX_GPJ_BASE,
275                 .chip   = {
276                         .base   = S3C64XX_GPJ(0),
277                         .ngpio  = S3C64XX_GPIO_J_NR,
278                         .label  = "GPJ",
279                 },
280         }, {
281                 .base   = S3C64XX_GPN_BASE,
282                 .chip   = {
283                         .base   = S3C64XX_GPN(0),
284                         .ngpio  = S3C64XX_GPIO_N_NR,
285                         .label  = "GPN",
286                 },
287         }, {
288                 .base   = S3C64XX_GPO_BASE,
289                 .chip   = {
290                         .base   = S3C64XX_GPO(0),
291                         .ngpio  = S3C64XX_GPIO_O_NR,
292                         .label  = "GPO",
293                 },
294         }, {
295                 .base   = S3C64XX_GPP_BASE,
296                 .chip   = {
297                         .base   = S3C64XX_GPP(0),
298                         .ngpio  = S3C64XX_GPIO_P_NR,
299                         .label  = "GPP",
300                 },
301         }, {
302                 .base   = S3C64XX_GPQ_BASE,
303                 .chip   = {
304                         .base   = S3C64XX_GPQ(0),
305                         .ngpio  = S3C64XX_GPIO_Q_NR,
306                         .label  = "GPQ",
307                 },
308         },
309 };
310
311 static __init void s3c64xx_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
312 {
313         chip->chip.direction_input = s3c64xx_gpiolib_4bit_input;
314         chip->chip.direction_output = s3c64xx_gpiolib_4bit_output;
315 }
316
317 static __init void s3c64xx_gpiolib_add_4bit2(struct s3c_gpio_chip *chip)
318 {
319         chip->chip.direction_input = s3c64xx_gpiolib_4bit2_input;
320         chip->chip.direction_output = s3c64xx_gpiolib_4bit2_output;
321 }
322
323 static __init void s3c64xx_gpiolib_add(struct s3c_gpio_chip *chips,
324                                        int nr_chips,
325                                        void (*fn)(struct s3c_gpio_chip *))
326 {
327         for (; nr_chips > 0; nr_chips--, chips++) {
328                 if (fn)
329                         (fn)(chips);
330                 s3c_gpiolib_add(chips);
331         }
332 }
333
334 static __init int s3c64xx_gpiolib_init(void)
335 {
336         s3c64xx_gpiolib_add(gpio_4bit, ARRAY_SIZE(gpio_4bit),
337                             s3c64xx_gpiolib_add_4bit);
338
339         s3c64xx_gpiolib_add(gpio_4bit2, ARRAY_SIZE(gpio_4bit2),
340                             s3c64xx_gpiolib_add_4bit2);
341
342         s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit), NULL);
343
344         return 0;
345 }
346
347 arch_initcall(s3c64xx_gpiolib_init);