gpiolib.c 10 KB

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