gpio-msm-common.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. /* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. */
  13. #include <linux/bitmap.h>
  14. #include <linux/bitops.h>
  15. #include <linux/gpio.h>
  16. #include <linux/init.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/irq.h>
  19. #include <linux/io.h>
  20. #include <linux/module.h>
  21. #include <linux/spinlock.h>
  22. #include <linux/syscore_ops.h>
  23. #include <linux/irqdomain.h>
  24. #include <linux/of.h>
  25. #include <linux/err.h>
  26. #include <linux/platform_device.h>
  27. #include <linux/slab.h>
  28. #include <linux/wakeup_reason.h>
  29. #include <asm/mach/irq.h>
  30. #include <mach/msm_iomap.h>
  31. #include <mach/gpiomux.h>
  32. #include <mach/mpm.h>
  33. #include "gpio-msm-common.h"
  34. #ifdef CONFIG_GPIO_MSM_V3
  35. enum msm_tlmm_register {
  36. SDC4_HDRV_PULL_CTL = 0x0, /* NOT USED */
  37. SDC3_HDRV_PULL_CTL = 0x0, /* NOT USED */
  38. SDC2_HDRV_PULL_CTL = 0x2048,
  39. SDC1_HDRV_PULL_CTL = 0x2044,
  40. };
  41. #else
  42. enum msm_tlmm_register {
  43. SDC4_HDRV_PULL_CTL = 0x20a0,
  44. SDC3_HDRV_PULL_CTL = 0x20a4,
  45. SDC2_HDRV_PULL_CTL = 0x0, /* NOT USED */
  46. SDC1_HDRV_PULL_CTL = 0x20a0,
  47. };
  48. #endif
  49. static int tlmm_msm_summary_irq, nr_direct_connect_irqs;
  50. struct tlmm_field_cfg {
  51. enum msm_tlmm_register reg;
  52. u8 off;
  53. };
  54. static const struct tlmm_field_cfg tlmm_hdrv_cfgs[] = {
  55. {SDC4_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC4_CLK */
  56. {SDC4_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC4_CMD */
  57. {SDC4_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC4_DATA */
  58. {SDC3_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC3_CLK */
  59. {SDC3_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC3_CMD */
  60. {SDC3_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC3_DATA */
  61. {SDC2_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC2_CLK */
  62. {SDC2_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC2_CMD */
  63. {SDC2_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC2_DATA */
  64. {SDC1_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC1_CLK */
  65. {SDC1_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC1_CMD */
  66. {SDC1_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC1_DATA */
  67. };
  68. static const struct tlmm_field_cfg tlmm_pull_cfgs[] = {
  69. {SDC4_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC4_CLK */
  70. {SDC4_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC4_CMD */
  71. {SDC4_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC4_DATA */
  72. {SDC3_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC3_CLK */
  73. {SDC3_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC3_CMD */
  74. {SDC3_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC3_DATA */
  75. {SDC2_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC2_CLK */
  76. {SDC2_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC2_CMD */
  77. {SDC2_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC2_DATA */
  78. {SDC1_HDRV_PULL_CTL, 13}, /* TLMM_PULL_SDC1_CLK */
  79. {SDC1_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC1_CMD */
  80. {SDC1_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC1_DATA */
  81. {SDC1_HDRV_PULL_CTL, 15}, /* TLMM_PULL_SDC1_RCLK */
  82. };
  83. /*
  84. * Supported arch specific irq extension.
  85. * Default make them NULL.
  86. */
  87. struct irq_chip msm_gpio_irq_extn = {
  88. .irq_eoi = NULL,
  89. .irq_mask = NULL,
  90. .irq_unmask = NULL,
  91. .irq_retrigger = NULL,
  92. .irq_set_type = NULL,
  93. .irq_set_wake = NULL,
  94. .irq_disable = NULL,
  95. };
  96. /**
  97. * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure
  98. *
  99. * @enabled_irqs: a bitmap used to optimize the summary-irq handler. By
  100. * keeping track of which gpios are unmasked as irq sources, we avoid
  101. * having to do __raw_readl calls on hundreds of iomapped registers each time
  102. * the summary interrupt fires in order to locate the active interrupts.
  103. *
  104. * @wake_irqs: a bitmap for tracking which interrupt lines are enabled
  105. * as wakeup sources. When the device is suspended, interrupts which are
  106. * not wakeup sources are disabled.
  107. */
  108. struct msm_gpio_dev {
  109. struct gpio_chip gpio_chip;
  110. unsigned long *enabled_irqs;
  111. unsigned long *wake_irqs;
  112. struct irq_domain *domain;
  113. };
  114. static DEFINE_SPINLOCK(tlmm_lock);
  115. static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip)
  116. {
  117. return container_of(chip, struct msm_gpio_dev, gpio_chip);
  118. }
  119. static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
  120. {
  121. int rc;
  122. rc = __msm_gpio_get_inout(offset);
  123. mb();
  124. return rc;
  125. }
  126. static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
  127. {
  128. __msm_gpio_set_inout(offset, val);
  129. mb();
  130. }
  131. static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
  132. {
  133. unsigned long irq_flags;
  134. spin_lock_irqsave(&tlmm_lock, irq_flags);
  135. __msm_gpio_set_config_direction(offset, 1, 0);
  136. mb();
  137. spin_unlock_irqrestore(&tlmm_lock, irq_flags);
  138. return 0;
  139. }
  140. static int msm_gpio_direction_output(struct gpio_chip *chip,
  141. unsigned offset,
  142. int val)
  143. {
  144. unsigned long irq_flags;
  145. spin_lock_irqsave(&tlmm_lock, irq_flags);
  146. __msm_gpio_set_config_direction(offset, 0, val);
  147. mb();
  148. spin_unlock_irqrestore(&tlmm_lock, irq_flags);
  149. return 0;
  150. }
  151. #ifdef CONFIG_OF
  152. static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
  153. {
  154. struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
  155. struct irq_domain *domain = g_dev->domain;
  156. return irq_create_mapping(domain, offset);
  157. }
  158. static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
  159. {
  160. struct irq_data *irq_data = irq_get_irq_data(irq);
  161. return irq_data->hwirq;
  162. }
  163. #else
  164. static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
  165. {
  166. return MSM_GPIO_TO_INT(offset - chip->base);
  167. }
  168. static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
  169. {
  170. return irq - MSM_GPIO_TO_INT(chip->base);
  171. }
  172. #endif
  173. static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
  174. {
  175. return msm_gpiomux_get(chip->base + offset);
  176. }
  177. static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
  178. {
  179. msm_gpiomux_put(chip->base + offset);
  180. }
  181. static struct msm_gpio_dev msm_gpio = {
  182. .gpio_chip = {
  183. .label = "msmgpio",
  184. .base = 0,
  185. .direction_input = msm_gpio_direction_input,
  186. .direction_output = msm_gpio_direction_output,
  187. .get = msm_gpio_get,
  188. .set = msm_gpio_set,
  189. .to_irq = msm_gpio_to_irq,
  190. .request = msm_gpio_request,
  191. .free = msm_gpio_free,
  192. },
  193. };
  194. static void msm_gpio_irq_ack(struct irq_data *d)
  195. {
  196. int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
  197. __msm_gpio_set_intr_status(gpio);
  198. mb();
  199. }
  200. static void msm_gpio_irq_mask(struct irq_data *d)
  201. {
  202. int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
  203. unsigned long irq_flags;
  204. spin_lock_irqsave(&tlmm_lock, irq_flags);
  205. __msm_gpio_set_intr_cfg_enable(gpio, 0);
  206. __clear_bit(gpio, msm_gpio.enabled_irqs);
  207. mb();
  208. spin_unlock_irqrestore(&tlmm_lock, irq_flags);
  209. if (msm_gpio_irq_extn.irq_mask)
  210. msm_gpio_irq_extn.irq_mask(d);
  211. }
  212. static void msm_gpio_irq_unmask(struct irq_data *d)
  213. {
  214. int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
  215. unsigned long irq_flags;
  216. spin_lock_irqsave(&tlmm_lock, irq_flags);
  217. __set_bit(gpio, msm_gpio.enabled_irqs);
  218. if (!__msm_gpio_get_intr_cfg_enable(gpio)) {
  219. __msm_gpio_set_intr_status(gpio);
  220. __msm_gpio_set_intr_cfg_enable(gpio, 1);
  221. mb();
  222. }
  223. spin_unlock_irqrestore(&tlmm_lock, irq_flags);
  224. if (msm_gpio_irq_extn.irq_mask)
  225. msm_gpio_irq_extn.irq_unmask(d);
  226. }
  227. static void msm_gpio_irq_disable(struct irq_data *d)
  228. {
  229. if (msm_gpio_irq_extn.irq_disable)
  230. msm_gpio_irq_extn.irq_disable(d);
  231. }
  232. static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
  233. {
  234. int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
  235. unsigned long irq_flags;
  236. spin_lock_irqsave(&tlmm_lock, irq_flags);
  237. if (flow_type & IRQ_TYPE_EDGE_BOTH)
  238. __irq_set_handler_locked(d->irq, handle_edge_irq);
  239. else
  240. __irq_set_handler_locked(d->irq, handle_level_irq);
  241. __msm_gpio_set_intr_cfg_type(gpio, flow_type);
  242. mb();
  243. spin_unlock_irqrestore(&tlmm_lock, irq_flags);
  244. if (msm_gpio_irq_extn.irq_set_type)
  245. msm_gpio_irq_extn.irq_set_type(d, flow_type);
  246. return 0;
  247. }
  248. /*
  249. * When the summary IRQ is raised, any number of GPIO lines may be high.
  250. * It is the job of the summary handler to find all those GPIO lines
  251. * which have been set as summary IRQ lines and which are triggered,
  252. * and to call their interrupt handlers.
  253. */
  254. static irqreturn_t msm_summary_irq_handler(int irq, void *data)
  255. {
  256. unsigned long i;
  257. struct irq_desc *desc = irq_to_desc(irq);
  258. struct irq_chip *chip = irq_desc_get_chip(desc);
  259. int ngpio = msm_gpio.gpio_chip.ngpio;
  260. chained_irq_enter(chip, desc);
  261. for (i = find_first_bit(msm_gpio.enabled_irqs, ngpio);
  262. i < ngpio;
  263. i = find_next_bit(msm_gpio.enabled_irqs, ngpio, i + 1)) {
  264. if (__msm_gpio_get_intr_status(i))
  265. generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
  266. i));
  267. }
  268. chained_irq_exit(chip, desc);
  269. return IRQ_HANDLED;
  270. }
  271. static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
  272. {
  273. int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
  274. int ngpio = msm_gpio.gpio_chip.ngpio;
  275. if (on) {
  276. if (bitmap_empty(msm_gpio.wake_irqs, ngpio))
  277. irq_set_irq_wake(tlmm_msm_summary_irq, 1);
  278. set_bit(gpio, msm_gpio.wake_irqs);
  279. } else {
  280. clear_bit(gpio, msm_gpio.wake_irqs);
  281. if (bitmap_empty(msm_gpio.wake_irqs, ngpio))
  282. irq_set_irq_wake(tlmm_msm_summary_irq, 0);
  283. }
  284. if (msm_gpio_irq_extn.irq_set_wake)
  285. msm_gpio_irq_extn.irq_set_wake(d, on);
  286. return 0;
  287. }
  288. static struct irq_chip msm_gpio_irq_chip = {
  289. .name = "msmgpio",
  290. .irq_mask = msm_gpio_irq_mask,
  291. .irq_unmask = msm_gpio_irq_unmask,
  292. .irq_ack = msm_gpio_irq_ack,
  293. .irq_set_type = msm_gpio_irq_set_type,
  294. .irq_set_wake = msm_gpio_irq_set_wake,
  295. .irq_disable = msm_gpio_irq_disable,
  296. };
  297. #ifdef CONFIG_PM
  298. static int msm_gpio_suspend(void)
  299. {
  300. unsigned long irq_flags;
  301. unsigned long i;
  302. int ngpio = msm_gpio.gpio_chip.ngpio;
  303. spin_lock_irqsave(&tlmm_lock, irq_flags);
  304. for_each_set_bit(i, msm_gpio.enabled_irqs, ngpio)
  305. __msm_gpio_set_intr_cfg_enable(i, 0);
  306. for_each_set_bit(i, msm_gpio.wake_irqs, ngpio)
  307. __msm_gpio_set_intr_cfg_enable(i, 1);
  308. mb();
  309. spin_unlock_irqrestore(&tlmm_lock, irq_flags);
  310. return 0;
  311. }
  312. void msm_gpio_show_resume_irq(void)
  313. {
  314. unsigned long irq_flags;
  315. int i, irq, intstat;
  316. int ngpio = msm_gpio.gpio_chip.ngpio;
  317. if (!msm_show_resume_irq_mask)
  318. return;
  319. spin_lock_irqsave(&tlmm_lock, irq_flags);
  320. for_each_set_bit(i, msm_gpio.wake_irqs, ngpio) {
  321. intstat = __msm_gpio_get_intr_status(i);
  322. if (intstat) {
  323. irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
  324. #ifdef CONFIG_SEC_PM_DEBUG
  325. log_wakeup_reason(irq);
  326. update_wakeup_reason_stats(irq);
  327. #endif
  328. }
  329. }
  330. spin_unlock_irqrestore(&tlmm_lock, irq_flags);
  331. }
  332. static void msm_gpio_resume(void)
  333. {
  334. unsigned long irq_flags;
  335. unsigned long i;
  336. int ngpio = msm_gpio.gpio_chip.ngpio;
  337. msm_gpio_show_resume_irq();
  338. spin_lock_irqsave(&tlmm_lock, irq_flags);
  339. for_each_set_bit(i, msm_gpio.wake_irqs, ngpio)
  340. __msm_gpio_set_intr_cfg_enable(i, 0);
  341. for_each_set_bit(i, msm_gpio.enabled_irqs, ngpio)
  342. __msm_gpio_set_intr_cfg_enable(i, 1);
  343. mb();
  344. spin_unlock_irqrestore(&tlmm_lock, irq_flags);
  345. }
  346. #else
  347. #define msm_gpio_suspend NULL
  348. #define msm_gpio_resume NULL
  349. #endif
  350. static struct syscore_ops msm_gpio_syscore_ops = {
  351. .suspend = msm_gpio_suspend,
  352. .resume = msm_gpio_resume,
  353. };
  354. static void msm_tlmm_set_field(const struct tlmm_field_cfg *configs,
  355. unsigned id, unsigned width, unsigned val)
  356. {
  357. unsigned long irqflags;
  358. u32 mask = (1 << width) - 1;
  359. u32 __iomem *reg = MSM_TLMM_BASE + configs[id].reg;
  360. u32 reg_val;
  361. spin_lock_irqsave(&tlmm_lock, irqflags);
  362. reg_val = __raw_readl(reg);
  363. reg_val &= ~(mask << configs[id].off);
  364. reg_val |= (val & mask) << configs[id].off;
  365. __raw_writel(reg_val, reg);
  366. mb();
  367. spin_unlock_irqrestore(&tlmm_lock, irqflags);
  368. }
  369. void msm_tlmm_set_hdrive(enum msm_tlmm_hdrive_tgt tgt, int drv_str)
  370. {
  371. msm_tlmm_set_field(tlmm_hdrv_cfgs, tgt, 3, drv_str);
  372. }
  373. EXPORT_SYMBOL(msm_tlmm_set_hdrive);
  374. void msm_tlmm_set_pull(enum msm_tlmm_pull_tgt tgt, int pull)
  375. {
  376. msm_tlmm_set_field(tlmm_pull_cfgs, tgt, 2, pull);
  377. }
  378. EXPORT_SYMBOL(msm_tlmm_set_pull);
  379. int gpio_tlmm_config(unsigned config, unsigned disable)
  380. {
  381. unsigned gpio = GPIO_PIN(config);
  382. int ngpio = msm_gpio.gpio_chip.ngpio;
  383. if (gpio > ngpio)
  384. return -EINVAL;
  385. __gpio_tlmm_config(config);
  386. mb();
  387. return 0;
  388. }
  389. EXPORT_SYMBOL(gpio_tlmm_config);
  390. int msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
  391. unsigned int input_polarity)
  392. {
  393. unsigned long irq_flags;
  394. int ngpio = msm_gpio.gpio_chip.ngpio;
  395. if (gpio >= ngpio || irq >= nr_direct_connect_irqs)
  396. return -EINVAL;
  397. spin_lock_irqsave(&tlmm_lock, irq_flags);
  398. __msm_gpio_install_direct_irq(gpio, irq, input_polarity);
  399. mb();
  400. spin_unlock_irqrestore(&tlmm_lock, irq_flags);
  401. return 0;
  402. }
  403. EXPORT_SYMBOL(msm_gpio_install_direct_irq);
  404. /*
  405. * This lock class tells lockdep that GPIO irqs are in a different
  406. * category than their parent, so it won't report false recursion.
  407. */
  408. static struct lock_class_key msm_gpio_lock_class;
  409. static inline void msm_gpio_set_irq_handler(struct device *dev)
  410. {
  411. int irq, i;
  412. if (!dev->of_node) {
  413. for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
  414. irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
  415. irq_set_lockdep_class(irq, &msm_gpio_lock_class);
  416. irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
  417. handle_level_irq);
  418. set_irq_flags(irq, IRQF_VALID);
  419. }
  420. }
  421. }
  422. static int __devinit msm_gpio_probe(struct platform_device *pdev)
  423. {
  424. int ret, ngpio = 0;
  425. struct msm_gpio_pdata *pdata = pdev->dev.platform_data;
  426. if (pdev->dev.of_node) {
  427. ret = of_property_read_u32(pdev->dev.of_node, "ngpio", &ngpio);
  428. if (ret) {
  429. pr_err("%s: Failed to find ngpio property\n", __func__);
  430. return ret;
  431. }
  432. ret = of_property_read_u32(pdev->dev.of_node,
  433. "qcom,direct-connect-irqs",
  434. &nr_direct_connect_irqs);
  435. if (ret) {
  436. pr_err("%s: Failed to find qcom,direct-connect-irqs property\n"
  437. , __func__);
  438. return ret;
  439. }
  440. } else {
  441. ngpio = pdata->ngpio;
  442. nr_direct_connect_irqs = pdata->direct_connect_irqs;
  443. }
  444. tlmm_msm_summary_irq = platform_get_irq(pdev, 0);
  445. if (tlmm_msm_summary_irq < 0) {
  446. pr_err("%s: No interrupt defined for msmgpio\n", __func__);
  447. return -ENXIO;
  448. }
  449. msm_gpio.gpio_chip.dev = &pdev->dev;
  450. msm_gpio.gpio_chip.ngpio = ngpio;
  451. spin_lock_init(&tlmm_lock);
  452. msm_gpio.enabled_irqs = devm_kzalloc(&pdev->dev, sizeof(unsigned long)
  453. * BITS_TO_LONGS(ngpio), GFP_KERNEL);
  454. if (!msm_gpio.enabled_irqs) {
  455. dev_err(&pdev->dev, "%s failed to allocated enabled_irqs bitmap\n"
  456. , __func__);
  457. return -ENOMEM;
  458. }
  459. msm_gpio.wake_irqs = devm_kzalloc(&pdev->dev, sizeof(unsigned long) *
  460. BITS_TO_LONGS(ngpio), GFP_KERNEL);
  461. if (!msm_gpio.wake_irqs) {
  462. dev_err(&pdev->dev, "%s failed to allocated wake_irqs bitmap\n"
  463. , __func__);
  464. return -ENOMEM;
  465. }
  466. bitmap_zero(msm_gpio.enabled_irqs, ngpio);
  467. bitmap_zero(msm_gpio.wake_irqs, ngpio);
  468. ret = gpiochip_add(&msm_gpio.gpio_chip);
  469. if (ret < 0)
  470. return ret;
  471. msm_gpio_set_irq_handler(&pdev->dev);
  472. ret = devm_request_irq(&pdev->dev, tlmm_msm_summary_irq,
  473. msm_summary_irq_handler, IRQF_TRIGGER_HIGH,
  474. "msmgpio", NULL);
  475. if (ret) {
  476. pr_err("Request_irq failed for tlmm_msm_summary_irq - %d\n",
  477. ret);
  478. return ret;
  479. }
  480. register_syscore_ops(&msm_gpio_syscore_ops);
  481. return 0;
  482. }
  483. #ifdef CONFIG_OF
  484. static struct of_device_id msm_gpio_of_match[] __devinitdata = {
  485. {.compatible = "qcom,msm-gpio", },
  486. { },
  487. };
  488. #endif
  489. static int __devexit msm_gpio_remove(struct platform_device *pdev)
  490. {
  491. int ret;
  492. unregister_syscore_ops(&msm_gpio_syscore_ops);
  493. ret = gpiochip_remove(&msm_gpio.gpio_chip);
  494. if (ret < 0)
  495. return ret;
  496. irq_set_handler(tlmm_msm_summary_irq, NULL);
  497. return 0;
  498. }
  499. static struct platform_driver msm_gpio_driver = {
  500. .probe = msm_gpio_probe,
  501. .remove = __devexit_p(msm_gpio_remove),
  502. .driver = {
  503. .name = "msmgpio",
  504. .owner = THIS_MODULE,
  505. .of_match_table = of_match_ptr(msm_gpio_of_match),
  506. },
  507. };
  508. static void __exit msm_gpio_exit(void)
  509. {
  510. platform_driver_unregister(&msm_gpio_driver);
  511. }
  512. module_exit(msm_gpio_exit);
  513. static int __init msm_gpio_init(void)
  514. {
  515. return platform_driver_register(&msm_gpio_driver);
  516. }
  517. postcore_initcall(msm_gpio_init);
  518. #ifdef CONFIG_OF
  519. static int msm_gpio_irq_domain_xlate(struct irq_domain *d,
  520. struct device_node *controller,
  521. const u32 *intspec,
  522. unsigned int intsize,
  523. unsigned long *out_hwirq,
  524. unsigned int *out_type)
  525. {
  526. if (d->of_node != controller)
  527. return -EINVAL;
  528. if (intsize != 2)
  529. return -EINVAL;
  530. /* hwirq value */
  531. *out_hwirq = intspec[0];
  532. /* irq flags */
  533. *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
  534. return 0;
  535. }
  536. static int msm_gpio_irq_domain_map(struct irq_domain *d, unsigned int irq,
  537. irq_hw_number_t hwirq)
  538. {
  539. irq_set_lockdep_class(irq, &msm_gpio_lock_class);
  540. irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
  541. handle_level_irq);
  542. set_irq_flags(irq, IRQF_VALID);
  543. return 0;
  544. }
  545. static struct irq_domain_ops msm_gpio_irq_domain_ops = {
  546. .xlate = msm_gpio_irq_domain_xlate,
  547. .map = msm_gpio_irq_domain_map,
  548. };
  549. int __init msm_gpio_of_init(struct device_node *node,
  550. struct device_node *parent)
  551. {
  552. int ngpio, ret;
  553. ret = of_property_read_u32(node, "ngpio", &ngpio);
  554. if (ret) {
  555. WARN(1, "Cannot get numgpios from device tree\n");
  556. return ret;
  557. }
  558. msm_gpio.domain = irq_domain_add_linear(node, ngpio,
  559. &msm_gpio_irq_domain_ops, &msm_gpio);
  560. if (!msm_gpio.domain) {
  561. WARN(1, "Cannot allocate irq_domain\n");
  562. return -ENOMEM;
  563. }
  564. return 0;
  565. }
  566. #endif
  567. MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
  568. MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs");
  569. MODULE_LICENSE("GPL v2");
  570. MODULE_ALIAS("sysdev:msmgpio");