gpio-s5p64x0.c 10 KB

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