Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gpiolib.c
Go to the documentation of this file.
1 /* linux/arch/arm/mach-s5p64x0/gpiolib.c
2  *
3  * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
4  * http://www.samsung.com
5  *
6  * S5P64X0 - GPIOlib 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 version 2 as
10  * published by the Free Software Foundation.
11 */
12 
13 #include <linux/kernel.h>
14 #include <linux/irq.h>
15 #include <linux/io.h>
16 #include <linux/gpio.h>
17 
18 #include <mach/map.h>
19 #include <mach/regs-gpio.h>
20 #include <mach/regs-clock.h>
21 
22 #include <plat/cpu.h>
23 #include <plat/gpio-core.h>
24 #include <plat/gpio-cfg.h>
25 #include <plat/gpio-cfg-helpers.h>
26 
27 /*
28  * S5P6440 GPIO bank summary:
29  *
30  * Bank GPIOs Style SlpCon ExtInt Group
31  * A 6 4Bit Yes 1
32  * B 7 4Bit Yes 1
33  * C 8 4Bit Yes 2
34  * F 2 2Bit Yes 4 [1]
35  * G 7 4Bit Yes 5
36  * H 10 4Bit[2] Yes 6
37  * I 16 2Bit Yes None
38  * J 12 2Bit Yes None
39  * N 16 2Bit No IRQ_EINT
40  * P 8 2Bit Yes 8
41  * R 15 4Bit[2] Yes 8
42  *
43  * S5P6450 GPIO bank summary:
44  *
45  * Bank GPIOs Style SlpCon ExtInt Group
46  * A 6 4Bit Yes 1
47  * B 7 4Bit Yes 1
48  * C 8 4Bit Yes 2
49  * D 8 4Bit Yes None
50  * F 2 2Bit Yes None
51  * G 14 4Bit[2] Yes 5
52  * H 10 4Bit[2] Yes 6
53  * I 16 2Bit Yes None
54  * J 12 2Bit Yes None
55  * K 5 4Bit Yes None
56  * N 16 2Bit No IRQ_EINT
57  * P 11 2Bit Yes 8
58  * Q 14 2Bit Yes None
59  * R 15 4Bit[2] Yes None
60  * S 8 2Bit Yes None
61  *
62  * [1] BANKF pins 14,15 do not form part of the external interrupt sources
63  * [2] BANK has two control registers, GPxCON0 and GPxCON1
64  */
65 
66 static int s5p64x0_gpiolib_rbank_4bit2_input(struct gpio_chip *chip,
67  unsigned int offset)
68 {
69  struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
70  void __iomem *base = ourchip->base;
71  void __iomem *regcon = base;
72  unsigned long con;
73  unsigned long flags;
74 
75  switch (offset) {
76  case 6:
77  offset += 1;
78  case 0:
79  case 1:
80  case 2:
81  case 3:
82  case 4:
83  case 5:
84  regcon -= 4;
85  break;
86  default:
87  offset -= 7;
88  break;
89  }
90 
91  s3c_gpio_lock(ourchip, flags);
92 
93  con = __raw_readl(regcon);
94  con &= ~(0xf << con_4bit_shift(offset));
95  __raw_writel(con, regcon);
96 
97  s3c_gpio_unlock(ourchip, flags);
98 
99  return 0;
100 }
101 
102 static int s5p64x0_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
103  unsigned int offset, int value)
104 {
105  struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
106  void __iomem *base = ourchip->base;
107  void __iomem *regcon = base;
108  unsigned long con;
109  unsigned long dat;
110  unsigned long flags;
111  unsigned con_offset = offset;
112 
113  switch (con_offset) {
114  case 6:
115  con_offset += 1;
116  case 0:
117  case 1:
118  case 2:
119  case 3:
120  case 4:
121  case 5:
122  regcon -= 4;
123  break;
124  default:
125  con_offset -= 7;
126  break;
127  }
128 
129  s3c_gpio_lock(ourchip, flags);
130 
131  con = __raw_readl(regcon);
132  con &= ~(0xf << con_4bit_shift(con_offset));
133  con |= 0x1 << con_4bit_shift(con_offset);
134 
135  dat = __raw_readl(base + GPIODAT_OFF);
136  if (value)
137  dat |= 1 << offset;
138  else
139  dat &= ~(1 << offset);
140 
141  __raw_writel(con, regcon);
142  __raw_writel(dat, base + GPIODAT_OFF);
143 
144  s3c_gpio_unlock(ourchip, flags);
145 
146  return 0;
147 }
148 
149 int s5p64x0_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip,
150  unsigned int off, unsigned int cfg)
151 {
152  void __iomem *reg = chip->base;
153  unsigned int shift;
154  u32 con;
155 
156  switch (off) {
157  case 0:
158  case 1:
159  case 2:
160  case 3:
161  case 4:
162  case 5:
163  shift = (off & 7) * 4;
164  reg -= 4;
165  break;
166  case 6:
167  shift = ((off + 1) & 7) * 4;
168  reg -= 4;
169  default:
170  shift = ((off + 1) & 7) * 4;
171  break;
172  }
173 
174  if (s3c_gpio_is_cfg_special(cfg)) {
175  cfg &= 0xf;
176  cfg <<= shift;
177  }
178 
179  con = __raw_readl(reg);
180  con &= ~(0xf << shift);
181  con |= cfg;
182  __raw_writel(con, reg);
183 
184  return 0;
185 }
186 
187 static struct s3c_gpio_cfg s5p64x0_gpio_cfgs[] = {
188  {
189  .cfg_eint = 0,
190  }, {
191  .cfg_eint = 7,
192  }, {
193  .cfg_eint = 3,
194  .set_config = s5p64x0_gpio_setcfg_4bit_rbank,
195  }, {
196  .cfg_eint = 0,
197  .set_config = s3c_gpio_setcfg_s3c24xx,
198  .get_config = s3c_gpio_getcfg_s3c24xx,
199  }, {
200  .cfg_eint = 2,
201  .set_config = s3c_gpio_setcfg_s3c24xx,
202  .get_config = s3c_gpio_getcfg_s3c24xx,
203  }, {
204  .cfg_eint = 3,
205  .set_config = s3c_gpio_setcfg_s3c24xx,
206  .get_config = s3c_gpio_getcfg_s3c24xx,
207  },
208 };
209 
210 static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
211  {
212  .base = S5P64X0_GPA_BASE,
213  .config = &s5p64x0_gpio_cfgs[1],
214  .chip = {
215  .base = S5P6440_GPA(0),
216  .ngpio = S5P6440_GPIO_A_NR,
217  .label = "GPA",
218  },
219  }, {
220  .base = S5P64X0_GPB_BASE,
221  .config = &s5p64x0_gpio_cfgs[1],
222  .chip = {
223  .base = S5P6440_GPB(0),
224  .ngpio = S5P6440_GPIO_B_NR,
225  .label = "GPB",
226  },
227  }, {
228  .base = S5P64X0_GPC_BASE,
229  .config = &s5p64x0_gpio_cfgs[1],
230  .chip = {
231  .base = S5P6440_GPC(0),
232  .ngpio = S5P6440_GPIO_C_NR,
233  .label = "GPC",
234  },
235  }, {
236  .base = S5P64X0_GPG_BASE,
237  .config = &s5p64x0_gpio_cfgs[1],
238  .chip = {
239  .base = S5P6440_GPG(0),
240  .ngpio = S5P6440_GPIO_G_NR,
241  .label = "GPG",
242  },
243  },
244 };
245 
246 static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = {
247  {
248  .base = S5P64X0_GPH_BASE + 0x4,
249  .config = &s5p64x0_gpio_cfgs[1],
250  .chip = {
251  .base = S5P6440_GPH(0),
252  .ngpio = S5P6440_GPIO_H_NR,
253  .label = "GPH",
254  },
255  },
256 };
257 
258 static struct s3c_gpio_chip s5p6440_gpio_rbank_4bit2[] = {
259  {
260  .base = S5P64X0_GPR_BASE + 0x4,
261  .config = &s5p64x0_gpio_cfgs[2],
262  .chip = {
263  .base = S5P6440_GPR(0),
264  .ngpio = S5P6440_GPIO_R_NR,
265  .label = "GPR",
266  },
267  },
268 };
269 
270 static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
271  {
272  .base = S5P64X0_GPF_BASE,
273  .config = &s5p64x0_gpio_cfgs[5],
274  .chip = {
275  .base = S5P6440_GPF(0),
276  .ngpio = S5P6440_GPIO_F_NR,
277  .label = "GPF",
278  },
279  }, {
280  .base = S5P64X0_GPI_BASE,
281  .config = &s5p64x0_gpio_cfgs[3],
282  .chip = {
283  .base = S5P6440_GPI(0),
284  .ngpio = S5P6440_GPIO_I_NR,
285  .label = "GPI",
286  },
287  }, {
288  .base = S5P64X0_GPJ_BASE,
289  .config = &s5p64x0_gpio_cfgs[3],
290  .chip = {
291  .base = S5P6440_GPJ(0),
292  .ngpio = S5P6440_GPIO_J_NR,
293  .label = "GPJ",
294  },
295  }, {
296  .base = S5P64X0_GPN_BASE,
297  .config = &s5p64x0_gpio_cfgs[4],
298  .chip = {
299  .base = S5P6440_GPN(0),
300  .ngpio = S5P6440_GPIO_N_NR,
301  .label = "GPN",
302  },
303  }, {
304  .base = S5P64X0_GPP_BASE,
305  .config = &s5p64x0_gpio_cfgs[5],
306  .chip = {
307  .base = S5P6440_GPP(0),
308  .ngpio = S5P6440_GPIO_P_NR,
309  .label = "GPP",
310  },
311  },
312 };
313 
314 static struct s3c_gpio_chip s5p6450_gpio_4bit[] = {
315  {
316  .base = S5P64X0_GPA_BASE,
317  .config = &s5p64x0_gpio_cfgs[1],
318  .chip = {
319  .base = S5P6450_GPA(0),
320  .ngpio = S5P6450_GPIO_A_NR,
321  .label = "GPA",
322  },
323  }, {
324  .base = S5P64X0_GPB_BASE,
325  .config = &s5p64x0_gpio_cfgs[1],
326  .chip = {
327  .base = S5P6450_GPB(0),
328  .ngpio = S5P6450_GPIO_B_NR,
329  .label = "GPB",
330  },
331  }, {
332  .base = S5P64X0_GPC_BASE,
333  .config = &s5p64x0_gpio_cfgs[1],
334  .chip = {
335  .base = S5P6450_GPC(0),
336  .ngpio = S5P6450_GPIO_C_NR,
337  .label = "GPC",
338  },
339  }, {
340  .base = S5P6450_GPD_BASE,
341  .config = &s5p64x0_gpio_cfgs[1],
342  .chip = {
343  .base = S5P6450_GPD(0),
344  .ngpio = S5P6450_GPIO_D_NR,
345  .label = "GPD",
346  },
347  }, {
348  .base = S5P6450_GPK_BASE,
349  .config = &s5p64x0_gpio_cfgs[1],
350  .chip = {
351  .base = S5P6450_GPK(0),
352  .ngpio = S5P6450_GPIO_K_NR,
353  .label = "GPK",
354  },
355  },
356 };
357 
358 static struct s3c_gpio_chip s5p6450_gpio_4bit2[] = {
359  {
360  .base = S5P64X0_GPG_BASE + 0x4,
361  .config = &s5p64x0_gpio_cfgs[1],
362  .chip = {
363  .base = S5P6450_GPG(0),
364  .ngpio = S5P6450_GPIO_G_NR,
365  .label = "GPG",
366  },
367  }, {
368  .base = S5P64X0_GPH_BASE + 0x4,
369  .config = &s5p64x0_gpio_cfgs[1],
370  .chip = {
371  .base = S5P6450_GPH(0),
372  .ngpio = S5P6450_GPIO_H_NR,
373  .label = "GPH",
374  },
375  },
376 };
377 
378 static struct s3c_gpio_chip s5p6450_gpio_rbank_4bit2[] = {
379  {
380  .base = S5P64X0_GPR_BASE + 0x4,
381  .config = &s5p64x0_gpio_cfgs[2],
382  .chip = {
383  .base = S5P6450_GPR(0),
384  .ngpio = S5P6450_GPIO_R_NR,
385  .label = "GPR",
386  },
387  },
388 };
389 
390 static struct s3c_gpio_chip s5p6450_gpio_2bit[] = {
391  {
392  .base = S5P64X0_GPF_BASE,
393  .config = &s5p64x0_gpio_cfgs[5],
394  .chip = {
395  .base = S5P6450_GPF(0),
396  .ngpio = S5P6450_GPIO_F_NR,
397  .label = "GPF",
398  },
399  }, {
400  .base = S5P64X0_GPI_BASE,
401  .config = &s5p64x0_gpio_cfgs[3],
402  .chip = {
403  .base = S5P6450_GPI(0),
404  .ngpio = S5P6450_GPIO_I_NR,
405  .label = "GPI",
406  },
407  }, {
408  .base = S5P64X0_GPJ_BASE,
409  .config = &s5p64x0_gpio_cfgs[3],
410  .chip = {
411  .base = S5P6450_GPJ(0),
412  .ngpio = S5P6450_GPIO_J_NR,
413  .label = "GPJ",
414  },
415  }, {
416  .base = S5P64X0_GPN_BASE,
417  .config = &s5p64x0_gpio_cfgs[4],
418  .chip = {
419  .base = S5P6450_GPN(0),
420  .ngpio = S5P6450_GPIO_N_NR,
421  .label = "GPN",
422  },
423  }, {
424  .base = S5P64X0_GPP_BASE,
425  .config = &s5p64x0_gpio_cfgs[5],
426  .chip = {
427  .base = S5P6450_GPP(0),
428  .ngpio = S5P6450_GPIO_P_NR,
429  .label = "GPP",
430  },
431  }, {
432  .base = S5P6450_GPQ_BASE,
433  .config = &s5p64x0_gpio_cfgs[4],
434  .chip = {
435  .base = S5P6450_GPQ(0),
436  .ngpio = S5P6450_GPIO_Q_NR,
437  .label = "GPQ",
438  },
439  }, {
440  .base = S5P6450_GPS_BASE,
441  .config = &s5p64x0_gpio_cfgs[5],
442  .chip = {
443  .base = S5P6450_GPS(0),
444  .ngpio = S5P6450_GPIO_S_NR,
445  .label = "GPS",
446  },
447  },
448 };
449 
450 void __init s5p64x0_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips)
451 {
452  for (; nr_chips > 0; nr_chips--, chipcfg++) {
453  if (!chipcfg->set_config)
454  chipcfg->set_config = s3c_gpio_setcfg_s3c64xx_4bit;
455  if (!chipcfg->get_config)
456  chipcfg->get_config = s3c_gpio_getcfg_s3c64xx_4bit;
457  if (!chipcfg->set_pull)
458  chipcfg->set_pull = s3c_gpio_setpull_updown;
459  if (!chipcfg->get_pull)
460  chipcfg->get_pull = s3c_gpio_getpull_updown;
461  }
462 }
463 
464 static void __init s5p64x0_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip,
465  int nr_chips)
466 {
467  for (; nr_chips > 0; nr_chips--, chip++) {
468  chip->chip.direction_input = s5p64x0_gpiolib_rbank_4bit2_input;
469  chip->chip.direction_output =
470  s5p64x0_gpiolib_rbank_4bit2_output;
471  s3c_gpiolib_add(chip);
472  }
473 }
474 
475 static int __init s5p64x0_gpiolib_init(void)
476 {
477  s5p64x0_gpiolib_set_cfg(s5p64x0_gpio_cfgs,
478  ARRAY_SIZE(s5p64x0_gpio_cfgs));
479 
480  if (soc_is_s5p6450()) {
481  samsung_gpiolib_add_2bit_chips(s5p6450_gpio_2bit,
482  ARRAY_SIZE(s5p6450_gpio_2bit));
483 
484  samsung_gpiolib_add_4bit_chips(s5p6450_gpio_4bit,
485  ARRAY_SIZE(s5p6450_gpio_4bit));
486 
487  samsung_gpiolib_add_4bit2_chips(s5p6450_gpio_4bit2,
488  ARRAY_SIZE(s5p6450_gpio_4bit2));
489 
490  s5p64x0_gpio_add_rbank_4bit2(s5p6450_gpio_rbank_4bit2,
491  ARRAY_SIZE(s5p6450_gpio_rbank_4bit2));
492  } else {
493  samsung_gpiolib_add_2bit_chips(s5p6440_gpio_2bit,
494  ARRAY_SIZE(s5p6440_gpio_2bit));
495 
496  samsung_gpiolib_add_4bit_chips(s5p6440_gpio_4bit,
497  ARRAY_SIZE(s5p6440_gpio_4bit));
498 
499  samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2,
500  ARRAY_SIZE(s5p6440_gpio_4bit2));
501 
502  s5p64x0_gpio_add_rbank_4bit2(s5p6440_gpio_rbank_4bit2,
503  ARRAY_SIZE(s5p6440_gpio_rbank_4bit2));
504  }
505 
506  return 0;
507 }
508 core_initcall(s5p64x0_gpiolib_init);