gpiolib.c 10 KB

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