gpio.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /* arch/arm/mach-s5p6440/gpio.c
  2. *
  3. * Copyright (c) 2009 Samsung Electronics Co., Ltd.
  4. * http://www.samsung.com/
  5. *
  6. * S5P6440 - 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. #include <linux/kernel.h>
  13. #include <linux/irq.h>
  14. #include <linux/io.h>
  15. #include <linux/gpio.h>
  16. #include <mach/map.h>
  17. #include <mach/regs-gpio.h>
  18. #include <plat/gpio-core.h>
  19. #include <plat/gpio-cfg.h>
  20. #include <plat/gpio-cfg-helpers.h>
  21. /* GPIO bank summary:
  22. *
  23. * Bank GPIOs Style SlpCon ExtInt Group
  24. * A 6 4Bit Yes 1
  25. * B 7 4Bit Yes 1
  26. * C 8 4Bit Yes 2
  27. * F 2 2Bit Yes 4 [1]
  28. * G 7 4Bit Yes 5
  29. * H 10 4Bit[2] Yes 6
  30. * I 16 2Bit Yes None
  31. * J 12 2Bit Yes None
  32. * N 16 2Bit No IRQ_EINT
  33. * P 8 2Bit Yes 8
  34. * R 15 4Bit[2] Yes 8
  35. *
  36. * [1] BANKF pins 14,15 do not form part of the external interrupt sources
  37. * [2] BANK has two control registers, GPxCON0 and GPxCON1
  38. */
  39. static int s5p6440_gpiolib_rbank_4bit2_input(struct gpio_chip *chip,
  40. unsigned int offset)
  41. {
  42. struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
  43. void __iomem *base = ourchip->base;
  44. void __iomem *regcon = base;
  45. unsigned long con;
  46. unsigned long flags;
  47. switch (offset) {
  48. case 6:
  49. offset += 1;
  50. case 0:
  51. case 1:
  52. case 2:
  53. case 3:
  54. case 4:
  55. case 5:
  56. regcon -= 4;
  57. break;
  58. default:
  59. offset -= 7;
  60. break;
  61. }
  62. s3c_gpio_lock(ourchip, flags);
  63. con = __raw_readl(regcon);
  64. con &= ~(0xf << con_4bit_shift(offset));
  65. __raw_writel(con, regcon);
  66. s3c_gpio_unlock(ourchip, flags);
  67. return 0;
  68. }
  69. static int s5p6440_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
  70. unsigned int offset, int value)
  71. {
  72. struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
  73. void __iomem *base = ourchip->base;
  74. void __iomem *regcon = base;
  75. unsigned long con;
  76. unsigned long dat;
  77. unsigned long flags;
  78. unsigned con_offset = offset;
  79. switch (con_offset) {
  80. case 6:
  81. con_offset += 1;
  82. case 0:
  83. case 1:
  84. case 2:
  85. case 3:
  86. case 4:
  87. case 5:
  88. regcon -= 4;
  89. break;
  90. default:
  91. con_offset -= 7;
  92. break;
  93. }
  94. s3c_gpio_lock(ourchip, flags);
  95. con = __raw_readl(regcon);
  96. con &= ~(0xf << con_4bit_shift(con_offset));
  97. con |= 0x1 << con_4bit_shift(con_offset);
  98. dat = __raw_readl(base + GPIODAT_OFF);
  99. if (value)
  100. dat |= 1 << offset;
  101. else
  102. dat &= ~(1 << offset);
  103. __raw_writel(con, regcon);
  104. __raw_writel(dat, base + GPIODAT_OFF);
  105. s3c_gpio_unlock(ourchip, flags);
  106. return 0;
  107. }
  108. int s5p6440_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip,
  109. unsigned int off, unsigned int cfg)
  110. {
  111. void __iomem *reg = chip->base;
  112. unsigned int shift;
  113. unsigned long flags;
  114. u32 con;
  115. switch (off) {
  116. case 0:
  117. case 1:
  118. case 2:
  119. case 3:
  120. case 4:
  121. case 5:
  122. shift = (off & 7) * 4;
  123. reg -= 4;
  124. break;
  125. case 6:
  126. shift = ((off + 1) & 7) * 4;
  127. reg -= 4;
  128. default:
  129. shift = ((off + 1) & 7) * 4;
  130. break;
  131. }
  132. if (s3c_gpio_is_cfg_special(cfg)) {
  133. cfg &= 0xf;
  134. cfg <<= shift;
  135. }
  136. s3c_gpio_lock(chip, flags);
  137. con = __raw_readl(reg);
  138. con &= ~(0xf << shift);
  139. con |= cfg;
  140. __raw_writel(con, reg);
  141. s3c_gpio_unlock(chip, flags);
  142. return 0;
  143. }
  144. static struct s3c_gpio_cfg s5p6440_gpio_cfgs[] = {
  145. {
  146. .cfg_eint = 0,
  147. }, {
  148. .cfg_eint = 7,
  149. }, {
  150. .cfg_eint = 3,
  151. .set_config = s5p6440_gpio_setcfg_4bit_rbank,
  152. }, {
  153. .cfg_eint = 0,
  154. .set_config = s3c_gpio_setcfg_s3c24xx,
  155. .get_config = s3c_gpio_getcfg_s3c24xx,
  156. }, {
  157. .cfg_eint = 2,
  158. .set_config = s3c_gpio_setcfg_s3c24xx,
  159. .get_config = s3c_gpio_getcfg_s3c24xx,
  160. }, {
  161. .cfg_eint = 3,
  162. .set_config = s3c_gpio_setcfg_s3c24xx,
  163. .get_config = s3c_gpio_getcfg_s3c24xx,
  164. },
  165. };
  166. static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
  167. {
  168. .base = S5P6440_GPA_BASE,
  169. .config = &s5p6440_gpio_cfgs[1],
  170. .chip = {
  171. .base = S5P6440_GPA(0),
  172. .ngpio = S5P6440_GPIO_A_NR,
  173. .label = "GPA",
  174. },
  175. }, {
  176. .base = S5P6440_GPB_BASE,
  177. .config = &s5p6440_gpio_cfgs[1],
  178. .chip = {
  179. .base = S5P6440_GPB(0),
  180. .ngpio = S5P6440_GPIO_B_NR,
  181. .label = "GPB",
  182. },
  183. }, {
  184. .base = S5P6440_GPC_BASE,
  185. .config = &s5p6440_gpio_cfgs[1],
  186. .chip = {
  187. .base = S5P6440_GPC(0),
  188. .ngpio = S5P6440_GPIO_C_NR,
  189. .label = "GPC",
  190. },
  191. }, {
  192. .base = S5P6440_GPG_BASE,
  193. .config = &s5p6440_gpio_cfgs[1],
  194. .chip = {
  195. .base = S5P6440_GPG(0),
  196. .ngpio = S5P6440_GPIO_G_NR,
  197. .label = "GPG",
  198. },
  199. },
  200. };
  201. static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = {
  202. {
  203. .base = S5P6440_GPH_BASE + 0x4,
  204. .config = &s5p6440_gpio_cfgs[1],
  205. .chip = {
  206. .base = S5P6440_GPH(0),
  207. .ngpio = S5P6440_GPIO_H_NR,
  208. .label = "GPH",
  209. },
  210. },
  211. };
  212. static struct s3c_gpio_chip gpio_rbank_4bit2[] = {
  213. {
  214. .base = S5P6440_GPR_BASE + 0x4,
  215. .config = &s5p6440_gpio_cfgs[2],
  216. .chip = {
  217. .base = S5P6440_GPR(0),
  218. .ngpio = S5P6440_GPIO_R_NR,
  219. .label = "GPR",
  220. },
  221. },
  222. };
  223. static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
  224. {
  225. .base = S5P6440_GPF_BASE,
  226. .config = &s5p6440_gpio_cfgs[5],
  227. .chip = {
  228. .base = S5P6440_GPF(0),
  229. .ngpio = S5P6440_GPIO_F_NR,
  230. .label = "GPF",
  231. },
  232. }, {
  233. .base = S5P6440_GPI_BASE,
  234. .config = &s5p6440_gpio_cfgs[3],
  235. .chip = {
  236. .base = S5P6440_GPI(0),
  237. .ngpio = S5P6440_GPIO_I_NR,
  238. .label = "GPI",
  239. },
  240. }, {
  241. .base = S5P6440_GPJ_BASE,
  242. .config = &s5p6440_gpio_cfgs[3],
  243. .chip = {
  244. .base = S5P6440_GPJ(0),
  245. .ngpio = S5P6440_GPIO_J_NR,
  246. .label = "GPJ",
  247. },
  248. }, {
  249. .base = S5P6440_GPN_BASE,
  250. .config = &s5p6440_gpio_cfgs[4],
  251. .chip = {
  252. .base = S5P6440_GPN(0),
  253. .ngpio = S5P6440_GPIO_N_NR,
  254. .label = "GPN",
  255. },
  256. }, {
  257. .base = S5P6440_GPP_BASE,
  258. .config = &s5p6440_gpio_cfgs[5],
  259. .chip = {
  260. .base = S5P6440_GPP(0),
  261. .ngpio = S5P6440_GPIO_P_NR,
  262. .label = "GPP",
  263. },
  264. },
  265. };
  266. void __init s5p6440_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips)
  267. {
  268. for (; nr_chips > 0; nr_chips--, chipcfg++) {
  269. if (!chipcfg->set_config)
  270. chipcfg->set_config = s3c_gpio_setcfg_s3c64xx_4bit;
  271. if (!chipcfg->get_config)
  272. chipcfg->get_config = s3c_gpio_getcfg_s3c64xx_4bit;
  273. if (!chipcfg->set_pull)
  274. chipcfg->set_pull = s3c_gpio_setpull_updown;
  275. if (!chipcfg->get_pull)
  276. chipcfg->get_pull = s3c_gpio_getpull_updown;
  277. }
  278. }
  279. static void __init s5p6440_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip,
  280. int nr_chips)
  281. {
  282. for (; nr_chips > 0; nr_chips--, chip++) {
  283. chip->chip.direction_input = s5p6440_gpiolib_rbank_4bit2_input;
  284. chip->chip.direction_output =
  285. s5p6440_gpiolib_rbank_4bit2_output;
  286. s3c_gpiolib_add(chip);
  287. }
  288. }
  289. static int __init s5p6440_gpiolib_init(void)
  290. {
  291. struct s3c_gpio_chip *chips = s5p6440_gpio_2bit;
  292. int nr_chips = ARRAY_SIZE(s5p6440_gpio_2bit);
  293. s5p6440_gpiolib_set_cfg(s5p6440_gpio_cfgs,
  294. ARRAY_SIZE(s5p6440_gpio_cfgs));
  295. for (; nr_chips > 0; nr_chips--, chips++)
  296. s3c_gpiolib_add(chips);
  297. samsung_gpiolib_add_4bit_chips(s5p6440_gpio_4bit,
  298. ARRAY_SIZE(s5p6440_gpio_4bit));
  299. samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2,
  300. ARRAY_SIZE(s5p6440_gpio_4bit2));
  301. s5p6440_gpio_add_rbank_4bit2(gpio_rbank_4bit2,
  302. ARRAY_SIZE(gpio_rbank_4bit2));
  303. return 0;
  304. }
  305. arch_initcall(s5p6440_gpiolib_init);