Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
[sfrench/cifs-2.6.git] / arch / arm / plat-s5pc1xx / gpiolib.c
1 /*
2  * arch/arm/plat-s5pc1xx/gpiolib.c
3  *
4  *  Copyright 2009 Samsung Electronics Co
5  *  Kyungmin Park <kyungmin.park@samsung.com>
6  *
7  * S5PC1XX - 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 version 2 as
11  * published by the Free Software Foundation.
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/irq.h>
16 #include <linux/io.h>
17 #include <linux/gpio.h>
18
19 #include <mach/map.h>
20 #include <mach/gpio-core.h>
21
22 #include <plat/gpio-cfg.h>
23 #include <plat/gpio-cfg-helpers.h>
24 #include <plat/regs-gpio.h>
25
26 /* S5PC100 GPIO bank summary:
27  *
28  * Bank GPIOs   Style   INT Type
29  * A0   8       4Bit    GPIO_INT0
30  * A1   5       4Bit    GPIO_INT1
31  * B    8       4Bit    GPIO_INT2
32  * C    5       4Bit    GPIO_INT3
33  * D    7       4Bit    GPIO_INT4
34  * E0   8       4Bit    GPIO_INT5
35  * E1   6       4Bit    GPIO_INT6
36  * F0   8       4Bit    GPIO_INT7
37  * F1   8       4Bit    GPIO_INT8
38  * F2   8       4Bit    GPIO_INT9
39  * F3   4       4Bit    GPIO_INT10
40  * G0   8       4Bit    GPIO_INT11
41  * G1   3       4Bit    GPIO_INT12
42  * G2   7       4Bit    GPIO_INT13
43  * G3   7       4Bit    GPIO_INT14
44  * H0   8       4Bit    WKUP_INT
45  * H1   8       4Bit    WKUP_INT
46  * H2   8       4Bit    WKUP_INT
47  * H3   8       4Bit    WKUP_INT
48  * I    8       4Bit    GPIO_INT15
49  * J0   8       4Bit    GPIO_INT16
50  * J1   5       4Bit    GPIO_INT17
51  * J2   8       4Bit    GPIO_INT18
52  * J3   8       4Bit    GPIO_INT19
53  * J4   4       4Bit    GPIO_INT20
54  * K0   8       4Bit    None
55  * K1   6       4Bit    None
56  * K2   8       4Bit    None
57  * K3   8       4Bit    None
58  * L0   8       4Bit    None
59  * L1   8       4Bit    None
60  * L2   8       4Bit    None
61  * L3   8       4Bit    None
62  */
63
64 #define OFF_GPCON       (0x00)
65 #define OFF_GPDAT       (0x04)
66
67 #define con_4bit_shift(__off) ((__off) * 4)
68
69 #if 1
70 #define gpio_dbg(x...) do { } while (0)
71 #else
72 #define gpio_dbg(x...) printk(KERN_DEBUG x)
73 #endif
74
75 /* The s5pc1xx_gpiolib routines are to control the gpio banks where
76  * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the
77  * following example:
78  *
79  * base + 0x00: Control register, 4 bits per gpio
80  *              gpio n: 4 bits starting at (4*n)
81  *              0000 = input, 0001 = output, others mean special-function
82  * base + 0x04: Data register, 1 bit per gpio
83  *              bit n: data bit n
84  *
85  * Note, since the data register is one bit per gpio and is at base + 0x4
86  * we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of
87  * the output.
88  */
89
90 static int s5pc1xx_gpiolib_input(struct gpio_chip *chip, unsigned offset)
91 {
92         struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
93         void __iomem *base = ourchip->base;
94         unsigned long con;
95
96         con = __raw_readl(base + OFF_GPCON);
97         con &= ~(0xf << con_4bit_shift(offset));
98         __raw_writel(con, base + OFF_GPCON);
99
100         gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con);
101
102         return 0;
103 }
104
105 static int s5pc1xx_gpiolib_output(struct gpio_chip *chip,
106                                        unsigned offset, int value)
107 {
108         struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
109         void __iomem *base = ourchip->base;
110         unsigned long con;
111         unsigned long dat;
112
113         con = __raw_readl(base + OFF_GPCON);
114         con &= ~(0xf << con_4bit_shift(offset));
115         con |= 0x1 << con_4bit_shift(offset);
116
117         dat = __raw_readl(base + OFF_GPDAT);
118         if (value)
119                 dat |= 1 << offset;
120         else
121                 dat &= ~(1 << offset);
122
123         __raw_writel(dat, base + OFF_GPDAT);
124         __raw_writel(con, base + OFF_GPCON);
125         __raw_writel(dat, base + OFF_GPDAT);
126
127         gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
128
129         return 0;
130 }
131
132 static int s5pc1xx_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset)
133 {
134         return S3C_IRQ_GPIO(chip->base + offset);
135 }
136
137 static int s5pc1xx_gpiolib_to_eint(struct gpio_chip *chip, unsigned int offset)
138 {
139         int base;
140
141         base = chip->base - S5PC100_GPH0(0);
142         if (base == 0)
143                 return IRQ_EINT(offset);
144         base = chip->base - S5PC100_GPH1(0);
145         if (base == 0)
146                 return IRQ_EINT(8 + offset);
147         base = chip->base - S5PC100_GPH2(0);
148         if (base == 0)
149                 return IRQ_EINT(16 + offset);
150         base = chip->base - S5PC100_GPH3(0);
151         if (base == 0)
152                 return IRQ_EINT(24 + offset);
153         return -EINVAL;
154 }
155
156 static struct s3c_gpio_cfg gpio_cfg = {
157         .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
158         .set_pull       = s3c_gpio_setpull_updown,
159         .get_pull       = s3c_gpio_getpull_updown,
160 };
161
162 static struct s3c_gpio_cfg gpio_cfg_eint = {
163         .cfg_eint       = 0xf,
164         .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
165         .set_pull       = s3c_gpio_setpull_updown,
166         .get_pull       = s3c_gpio_getpull_updown,
167 };
168
169 static struct s3c_gpio_cfg gpio_cfg_noint = {
170         .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
171         .set_pull       = s3c_gpio_setpull_updown,
172         .get_pull       = s3c_gpio_getpull_updown,
173 };
174
175 static struct s3c_gpio_chip s5pc100_gpio_chips[] = {
176         {
177                 .base   = S5PC100_GPA0_BASE,
178                 .config = &gpio_cfg,
179                 .chip   = {
180                         .base   = S5PC100_GPA0(0),
181                         .ngpio  = S5PC100_GPIO_A0_NR,
182                         .label  = "GPA0",
183                 },
184         }, {
185                 .base   = S5PC100_GPA1_BASE,
186                 .config = &gpio_cfg,
187                 .chip   = {
188                         .base   = S5PC100_GPA1(0),
189                         .ngpio  = S5PC100_GPIO_A1_NR,
190                         .label  = "GPA1",
191                 },
192         }, {
193                 .base   = S5PC100_GPB_BASE,
194                 .config = &gpio_cfg,
195                 .chip   = {
196                         .base   = S5PC100_GPB(0),
197                         .ngpio  = S5PC100_GPIO_B_NR,
198                         .label  = "GPB",
199                 },
200         }, {
201                 .base   = S5PC100_GPC_BASE,
202                 .config = &gpio_cfg,
203                 .chip   = {
204                         .base   = S5PC100_GPC(0),
205                         .ngpio  = S5PC100_GPIO_C_NR,
206                         .label  = "GPC",
207                 },
208         }, {
209                 .base   = S5PC100_GPD_BASE,
210                 .config = &gpio_cfg,
211                 .chip   = {
212                         .base   = S5PC100_GPD(0),
213                         .ngpio  = S5PC100_GPIO_D_NR,
214                         .label  = "GPD",
215                 },
216         }, {
217                 .base   = S5PC100_GPE0_BASE,
218                 .config = &gpio_cfg,
219                 .chip   = {
220                         .base   = S5PC100_GPE0(0),
221                         .ngpio  = S5PC100_GPIO_E0_NR,
222                         .label  = "GPE0",
223                 },
224         }, {
225                 .base   = S5PC100_GPE1_BASE,
226                 .config = &gpio_cfg,
227                 .chip   = {
228                         .base   = S5PC100_GPE1(0),
229                         .ngpio  = S5PC100_GPIO_E1_NR,
230                         .label  = "GPE1",
231                 },
232         }, {
233                 .base   = S5PC100_GPF0_BASE,
234                 .config = &gpio_cfg,
235                 .chip   = {
236                         .base   = S5PC100_GPF0(0),
237                         .ngpio  = S5PC100_GPIO_F0_NR,
238                         .label  = "GPF0",
239                 },
240         }, {
241                 .base   = S5PC100_GPF1_BASE,
242                 .config = &gpio_cfg,
243                 .chip   = {
244                         .base   = S5PC100_GPF1(0),
245                         .ngpio  = S5PC100_GPIO_F1_NR,
246                         .label  = "GPF1",
247                 },
248         }, {
249                 .base   = S5PC100_GPF2_BASE,
250                 .config = &gpio_cfg,
251                 .chip   = {
252                         .base   = S5PC100_GPF2(0),
253                         .ngpio  = S5PC100_GPIO_F2_NR,
254                         .label  = "GPF2",
255                 },
256         }, {
257                 .base   = S5PC100_GPF3_BASE,
258                 .config = &gpio_cfg,
259                 .chip   = {
260                         .base   = S5PC100_GPF3(0),
261                         .ngpio  = S5PC100_GPIO_F3_NR,
262                         .label  = "GPF3",
263                 },
264         }, {
265                 .base   = S5PC100_GPG0_BASE,
266                 .config = &gpio_cfg,
267                 .chip   = {
268                         .base   = S5PC100_GPG0(0),
269                         .ngpio  = S5PC100_GPIO_G0_NR,
270                         .label  = "GPG0",
271                 },
272         }, {
273                 .base   = S5PC100_GPG1_BASE,
274                 .config = &gpio_cfg,
275                 .chip   = {
276                         .base   = S5PC100_GPG1(0),
277                         .ngpio  = S5PC100_GPIO_G1_NR,
278                         .label  = "GPG1",
279                 },
280         }, {
281                 .base   = S5PC100_GPG2_BASE,
282                 .config = &gpio_cfg,
283                 .chip   = {
284                         .base   = S5PC100_GPG2(0),
285                         .ngpio  = S5PC100_GPIO_G2_NR,
286                         .label  = "GPG2",
287                 },
288         }, {
289                 .base   = S5PC100_GPG3_BASE,
290                 .config = &gpio_cfg,
291                 .chip   = {
292                         .base   = S5PC100_GPG3(0),
293                         .ngpio  = S5PC100_GPIO_G3_NR,
294                         .label  = "GPG3",
295                 },
296         }, {
297                 .base   = S5PC100_GPH0_BASE,
298                 .config = &gpio_cfg_eint,
299                 .chip   = {
300                         .base   = S5PC100_GPH0(0),
301                         .ngpio  = S5PC100_GPIO_H0_NR,
302                         .label  = "GPH0",
303                 },
304         }, {
305                 .base   = S5PC100_GPH1_BASE,
306                 .config = &gpio_cfg_eint,
307                 .chip   = {
308                         .base   = S5PC100_GPH1(0),
309                         .ngpio  = S5PC100_GPIO_H1_NR,
310                         .label  = "GPH1",
311                 },
312         }, {
313                 .base   = S5PC100_GPH2_BASE,
314                 .config = &gpio_cfg_eint,
315                 .chip   = {
316                         .base   = S5PC100_GPH2(0),
317                         .ngpio  = S5PC100_GPIO_H2_NR,
318                         .label  = "GPH2",
319                 },
320         }, {
321                 .base   = S5PC100_GPH3_BASE,
322                 .config = &gpio_cfg_eint,
323                 .chip   = {
324                         .base   = S5PC100_GPH3(0),
325                         .ngpio  = S5PC100_GPIO_H3_NR,
326                         .label  = "GPH3",
327                 },
328         }, {
329                 .base   = S5PC100_GPI_BASE,
330                 .config = &gpio_cfg,
331                 .chip   = {
332                         .base   = S5PC100_GPI(0),
333                         .ngpio  = S5PC100_GPIO_I_NR,
334                         .label  = "GPI",
335                 },
336         }, {
337                 .base   = S5PC100_GPJ0_BASE,
338                 .config = &gpio_cfg,
339                 .chip   = {
340                         .base   = S5PC100_GPJ0(0),
341                         .ngpio  = S5PC100_GPIO_J0_NR,
342                         .label  = "GPJ0",
343                 },
344         }, {
345                 .base   = S5PC100_GPJ1_BASE,
346                 .config = &gpio_cfg,
347                 .chip   = {
348                         .base   = S5PC100_GPJ1(0),
349                         .ngpio  = S5PC100_GPIO_J1_NR,
350                         .label  = "GPJ1",
351                 },
352         }, {
353                 .base   = S5PC100_GPJ2_BASE,
354                 .config = &gpio_cfg,
355                 .chip   = {
356                         .base   = S5PC100_GPJ2(0),
357                         .ngpio  = S5PC100_GPIO_J2_NR,
358                         .label  = "GPJ2",
359                 },
360         }, {
361                 .base   = S5PC100_GPJ3_BASE,
362                 .config = &gpio_cfg,
363                 .chip   = {
364                         .base   = S5PC100_GPJ3(0),
365                         .ngpio  = S5PC100_GPIO_J3_NR,
366                         .label  = "GPJ3",
367                 },
368         }, {
369                 .base   = S5PC100_GPJ4_BASE,
370                 .config = &gpio_cfg,
371                 .chip   = {
372                         .base   = S5PC100_GPJ4(0),
373                         .ngpio  = S5PC100_GPIO_J4_NR,
374                         .label  = "GPJ4",
375                 },
376         }, {
377                 .base   = S5PC100_GPK0_BASE,
378                 .config = &gpio_cfg_noint,
379                 .chip   = {
380                         .base   = S5PC100_GPK0(0),
381                         .ngpio  = S5PC100_GPIO_K0_NR,
382                         .label  = "GPK0",
383                 },
384         }, {
385                 .base   = S5PC100_GPK1_BASE,
386                 .config = &gpio_cfg_noint,
387                 .chip   = {
388                         .base   = S5PC100_GPK1(0),
389                         .ngpio  = S5PC100_GPIO_K1_NR,
390                         .label  = "GPK1",
391                 },
392         }, {
393                 .base   = S5PC100_GPK2_BASE,
394                 .config = &gpio_cfg_noint,
395                 .chip   = {
396                         .base   = S5PC100_GPK2(0),
397                         .ngpio  = S5PC100_GPIO_K2_NR,
398                         .label  = "GPK2",
399                 },
400         }, {
401                 .base   = S5PC100_GPK3_BASE,
402                 .config = &gpio_cfg_noint,
403                 .chip   = {
404                         .base   = S5PC100_GPK3(0),
405                         .ngpio  = S5PC100_GPIO_K3_NR,
406                         .label  = "GPK3",
407                 },
408         }, {
409                 .base   = S5PC100_GPL0_BASE,
410                 .config = &gpio_cfg_noint,
411                 .chip   = {
412                         .base   = S5PC100_GPL0(0),
413                         .ngpio  = S5PC100_GPIO_L0_NR,
414                         .label  = "GPL0",
415                 },
416         }, {
417                 .base   = S5PC100_GPL1_BASE,
418                 .config = &gpio_cfg_noint,
419                 .chip   = {
420                         .base   = S5PC100_GPL1(0),
421                         .ngpio  = S5PC100_GPIO_L1_NR,
422                         .label  = "GPL1",
423                 },
424         }, {
425                 .base   = S5PC100_GPL2_BASE,
426                 .config = &gpio_cfg_noint,
427                 .chip   = {
428                         .base   = S5PC100_GPL2(0),
429                         .ngpio  = S5PC100_GPIO_L2_NR,
430                         .label  = "GPL2",
431                 },
432         }, {
433                 .base   = S5PC100_GPL3_BASE,
434                 .config = &gpio_cfg_noint,
435                 .chip   = {
436                         .base   = S5PC100_GPL3(0),
437                         .ngpio  = S5PC100_GPIO_L3_NR,
438                         .label  = "GPL3",
439                 },
440         }, {
441                 .base   = S5PC100_GPL4_BASE,
442                 .config = &gpio_cfg_noint,
443                 .chip   = {
444                         .base   = S5PC100_GPL4(0),
445                         .ngpio  = S5PC100_GPIO_L4_NR,
446                         .label  = "GPL4",
447                 },
448         },
449 };
450
451 /* FIXME move from irq-gpio.c */
452 extern struct irq_chip s5pc1xx_gpioint;
453 extern void s5pc1xx_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc);
454
455 static __init void s5pc1xx_gpiolib_link(struct s3c_gpio_chip *chip)
456 {
457         chip->chip.direction_input = s5pc1xx_gpiolib_input;
458         chip->chip.direction_output = s5pc1xx_gpiolib_output;
459         chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
460
461         /* Interrupt */
462         if (chip->config == &gpio_cfg) {
463                 int i, irq;
464
465                 chip->chip.to_irq = s5pc1xx_gpiolib_to_irq;
466
467                 for (i = 0;  i < chip->chip.ngpio; i++) {
468                         irq = S3C_IRQ_GPIO_BASE + chip->chip.base + i;
469                         set_irq_chip(irq, &s5pc1xx_gpioint);
470                         set_irq_data(irq, &chip->chip);
471                         set_irq_handler(irq, handle_level_irq);
472                         set_irq_flags(irq, IRQF_VALID);
473                 }
474         } else if (chip->config == &gpio_cfg_eint)
475                 chip->chip.to_irq = s5pc1xx_gpiolib_to_eint;
476 }
477
478 static __init void s5pc1xx_gpiolib_add(struct s3c_gpio_chip *chips,
479                                        int nr_chips,
480                                        void (*fn)(struct s3c_gpio_chip *))
481 {
482         for (; nr_chips > 0; nr_chips--, chips++) {
483                 if (fn)
484                         (fn)(chips);
485                 s3c_gpiolib_add(chips);
486         }
487 }
488
489 static __init int s5pc1xx_gpiolib_init(void)
490 {
491         struct s3c_gpio_chip *chips;
492         int nr_chips;
493
494                 chips = s5pc100_gpio_chips;
495                 nr_chips = ARRAY_SIZE(s5pc100_gpio_chips);
496
497         s5pc1xx_gpiolib_add(chips, nr_chips, s5pc1xx_gpiolib_link);
498         /* Interrupt */
499         set_irq_chained_handler(IRQ_GPIOINT, s5pc1xx_irq_gpioint_handler);
500
501         return 0;
502 }
503 core_initcall(s5pc1xx_gpiolib_init);