/arch/arm/mach-fsm/msm8660-gpio.c

https://bitbucket.org/sammyz/iscream_thunderc-2.6.35-rebase · C · 337 lines · 250 code · 52 blank · 35 comment · 12 complexity · 1b28e48651fbcb9564f249fc43905abd MD5 · raw file

  1. /* Copyright (c) 2010, Code Aurora Forum. 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. * You should have received a copy of the GNU General Public License
  13. * along with this program; if not, write to the Free Software
  14. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15. * 02110-1301, USA.
  16. *
  17. */
  18. #include <linux/bitmap.h>
  19. #include <linux/gpio.h>
  20. #include <linux/init.h>
  21. #include <linux/irq.h>
  22. #include <linux/io.h>
  23. #include <linux/module.h>
  24. #include <linux/platform_device.h>
  25. #include <linux/spinlock.h>
  26. #include <linux/pm_runtime.h>
  27. #include <mach/msm_iomap.h>
  28. #include "tlmm-msm8660.h"
  29. #include "gpiomux.h"
  30. /**
  31. * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure
  32. *
  33. * @enabled_irqs: a bitmap used to optimize the summary-irq handler. By
  34. * keeping track of which gpios are unmasked as irq sources, we avoid
  35. * having to do readl calls on hundreds of iomapped registers each time
  36. * the summary interrupt fires in order to locate the active interrupts.
  37. *
  38. * @wake_irqs: a bitmap for tracking which interrupt lines are enabled
  39. * as wakeup sources. When the device is suspended, interrupts which are
  40. * not wakeup sources are disabled.
  41. */
  42. struct msm_gpio_dev {
  43. struct gpio_chip gpio_chip;
  44. spinlock_t lock;
  45. DECLARE_BITMAP(enabled_irqs, NR_MSM_GPIOS);
  46. DECLARE_BITMAP(wake_irqs, NR_MSM_GPIOS);
  47. };
  48. static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip)
  49. {
  50. return container_of(chip, struct msm_gpio_dev, gpio_chip);
  51. }
  52. static inline void set_gpio_bits(unsigned n, void __iomem *reg)
  53. {
  54. writel(readl(reg) | n, reg);
  55. }
  56. static inline void clr_gpio_bits(unsigned n, void __iomem *reg)
  57. {
  58. writel(readl(reg) & ~n, reg);
  59. }
  60. static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
  61. {
  62. return readl(GPIO_IN_OUT(offset)) & BIT(GPIO_IN_BIT);
  63. }
  64. static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
  65. {
  66. writel(val ? BIT(GPIO_OUT_BIT) : 0, GPIO_IN_OUT(offset));
  67. }
  68. static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
  69. {
  70. struct msm_gpio_dev *dev = to_msm_gpio_dev(chip);
  71. unsigned long irq_flags;
  72. spin_lock_irqsave(&dev->lock, irq_flags);
  73. clr_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(offset));
  74. spin_unlock_irqrestore(&dev->lock, irq_flags);
  75. return 0;
  76. }
  77. static int msm_gpio_direction_output(struct gpio_chip *chip,
  78. unsigned offset,
  79. int val)
  80. {
  81. struct msm_gpio_dev *dev = to_msm_gpio_dev(chip);
  82. unsigned long irq_flags;
  83. spin_lock_irqsave(&dev->lock, irq_flags);
  84. msm_gpio_set(chip, offset, val);
  85. set_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(offset));
  86. spin_unlock_irqrestore(&dev->lock, irq_flags);
  87. return 0;
  88. }
  89. static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
  90. {
  91. return MSM_GPIO_TO_INT(offset - chip->base);
  92. }
  93. static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
  94. {
  95. return irq - MSM_GPIO_TO_INT(chip->base);
  96. }
  97. static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
  98. {
  99. return msm_gpiomux_get(chip->base + offset);
  100. }
  101. static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
  102. {
  103. msm_gpiomux_put(chip->base + offset);
  104. }
  105. static struct msm_gpio_dev msm_gpio = {
  106. .gpio_chip = {
  107. .base = 0,
  108. .ngpio = NR_MSM_GPIOS,
  109. .direction_input = msm_gpio_direction_input,
  110. .direction_output = msm_gpio_direction_output,
  111. .get = msm_gpio_get,
  112. .set = msm_gpio_set,
  113. .to_irq = msm_gpio_to_irq,
  114. .request = msm_gpio_request,
  115. .free = msm_gpio_free,
  116. },
  117. };
  118. static void msm_gpio_irq_ack(unsigned int irq)
  119. {
  120. writel(BIT(INTR_STATUS_BIT),
  121. GPIO_INTR_STATUS(msm_irq_to_gpio(&msm_gpio.gpio_chip, irq)));
  122. }
  123. static void msm_gpio_irq_mask(unsigned int irq)
  124. {
  125. int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, irq);
  126. unsigned long irq_flags;
  127. spin_lock_irqsave(&msm_gpio.lock, irq_flags);
  128. writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio));
  129. clr_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
  130. __clear_bit(gpio, msm_gpio.enabled_irqs);
  131. spin_unlock_irqrestore(&msm_gpio.lock, irq_flags);
  132. }
  133. static void msm_gpio_irq_unmask(unsigned int irq)
  134. {
  135. int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, irq);
  136. unsigned long irq_flags;
  137. spin_lock_irqsave(&msm_gpio.lock, irq_flags);
  138. __set_bit(gpio, msm_gpio.enabled_irqs);
  139. set_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
  140. writel(TARGET_PROC_SCORPION, GPIO_INTR_CFG_SU(gpio));
  141. spin_unlock_irqrestore(&msm_gpio.lock, irq_flags);
  142. }
  143. static int msm_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
  144. {
  145. void *addr = GPIO_INTR_CFG(msm_irq_to_gpio(&msm_gpio.gpio_chip, irq));
  146. unsigned long irq_flags;
  147. uint32_t bits;
  148. if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
  149. return -EINVAL;
  150. spin_lock_irqsave(&msm_gpio.lock, irq_flags);
  151. bits = readl(addr);
  152. if (flow_type & IRQ_TYPE_EDGE_BOTH) {
  153. bits |= INTR_DECT_CTL_EDGE;
  154. irq_desc[irq].handle_irq = handle_edge_irq;
  155. } else {
  156. bits &= ~INTR_DECT_CTL_EDGE;
  157. irq_desc[irq].handle_irq = handle_level_irq;
  158. }
  159. if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
  160. bits |= INTR_POL_CTL_HI;
  161. else
  162. bits &= ~INTR_POL_CTL_HI;
  163. writel(bits, addr);
  164. spin_unlock_irqrestore(&msm_gpio.lock, irq_flags);
  165. return 0;
  166. }
  167. /*
  168. * When the summary IRQ is raised, any number of GPIO lines may be high.
  169. * It is the job of the summary handler to find all those GPIO lines
  170. * which have been set as summary IRQ lines and which are triggered,
  171. * and to call their interrupt handlers.
  172. */
  173. static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc)
  174. {
  175. unsigned long i;
  176. for (i = find_first_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
  177. i < NR_MSM_GPIOS;
  178. i = find_next_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS, i + 1)) {
  179. if (readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS_BIT))
  180. generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
  181. i));
  182. }
  183. desc->chip->ack(irq);
  184. }
  185. static int msm_gpio_irq_set_wake(unsigned int irq, unsigned int on)
  186. {
  187. int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, irq);
  188. if (on)
  189. set_bit(gpio, msm_gpio.wake_irqs);
  190. else
  191. clear_bit(gpio, msm_gpio.wake_irqs);
  192. return 0;
  193. }
  194. static struct irq_chip msm_gpio_irq_chip = {
  195. .name = "msm_gpio",
  196. .mask = msm_gpio_irq_mask,
  197. .unmask = msm_gpio_irq_unmask,
  198. .ack = msm_gpio_irq_ack,
  199. .set_type = msm_gpio_irq_set_type,
  200. .set_wake = msm_gpio_irq_set_wake,
  201. };
  202. static int __devinit msm_gpio_probe(struct platform_device *dev)
  203. {
  204. int i, irq, ret;
  205. spin_lock_init(&msm_gpio.lock);
  206. bitmap_zero(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
  207. bitmap_zero(msm_gpio.wake_irqs, NR_MSM_GPIOS);
  208. msm_gpio.gpio_chip.label = dev->name;
  209. ret = gpiochip_add(&msm_gpio.gpio_chip);
  210. if (ret < 0)
  211. return ret;
  212. for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
  213. irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
  214. set_irq_chip(irq, &msm_gpio_irq_chip);
  215. set_irq_handler(irq, handle_level_irq);
  216. set_irq_flags(irq, IRQF_VALID);
  217. }
  218. ret = pm_runtime_set_active(&dev->dev);
  219. if (ret < 0)
  220. printk(KERN_ERR "pm_runtime: fail to set active\n");
  221. pm_runtime_enable(&dev->dev);
  222. pm_runtime_get(&dev->dev);
  223. set_irq_chained_handler(TLMM_SCSS_SUMMARY_IRQ,
  224. msm_summary_irq_handler);
  225. return 0;
  226. }
  227. static int __devexit msm_gpio_remove(struct platform_device *dev)
  228. {
  229. int ret = gpiochip_remove(&msm_gpio.gpio_chip);
  230. if (ret < 0)
  231. return ret;
  232. set_irq_handler(TLMM_SCSS_SUMMARY_IRQ, NULL);
  233. pm_runtime_put(&dev->dev);
  234. pm_runtime_disable(&dev->dev);
  235. return 0;
  236. }
  237. #ifdef CONFIG_PM_RUNTIME
  238. static int msm_gpio_runtime_suspend(struct device *dev)
  239. {
  240. dev_dbg(dev, "pm_runtime: suspending...\n");
  241. return 0;
  242. }
  243. static int msm_gpio_runtime_resume(struct device *dev)
  244. {
  245. dev_dbg(dev, "pm_runtime: resuming...\n");
  246. return 0;
  247. }
  248. static int msm_gpio_runtime_idle(struct device *dev)
  249. {
  250. dev_dbg(dev, "pm_runtime: idling...\n");
  251. return 0;
  252. }
  253. #else
  254. #define msm_gpio_runtime_suspend NULL
  255. #define msm_gpio_runtime_resume NULL
  256. #define msm_gpio_runtime_idle NULL
  257. #endif
  258. static struct dev_pm_ops msm_gpio_dev_pm_ops = {
  259. .runtime_suspend = msm_gpio_runtime_suspend,
  260. .runtime_resume = msm_gpio_runtime_resume,
  261. .runtime_idle = msm_gpio_runtime_idle,
  262. };
  263. static struct platform_driver msm_gpio_driver = {
  264. .probe = msm_gpio_probe,
  265. .remove = __devexit_p(msm_gpio_remove),
  266. .driver = {
  267. .name = "msm8660-gpio",
  268. .owner = THIS_MODULE,
  269. .pm = &msm_gpio_dev_pm_ops,
  270. },
  271. };
  272. static int __init msm_gpio_init(void)
  273. {
  274. return platform_driver_register(&msm_gpio_driver);
  275. }
  276. static void __exit msm_gpio_exit(void)
  277. {
  278. platform_driver_unregister(&msm_gpio_driver);
  279. }
  280. postcore_initcall(msm_gpio_init);
  281. module_exit(msm_gpio_exit);
  282. MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
  283. MODULE_DESCRIPTION("Driver for Qualcomm MSM 8660-family SoC GPIOs");
  284. MODULE_LICENSE("GPL v2");
  285. MODULE_ALIAS("platform:msm8660-gpio");