jz4740-adc.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /*
  2. * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
  3. * JZ4740 SoC ADC driver
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation; either version 2 of the License, or (at your
  8. * option) any later version.
  9. *
  10. * You should have received a copy of the GNU General Public License along
  11. * with this program; if not, write to the Free Software Foundation, Inc.,
  12. * 675 Mass Ave, Cambridge, MA 02139, USA.
  13. *
  14. * This driver synchronizes access to the JZ4740 ADC core between the
  15. * JZ4740 battery and hwmon drivers.
  16. */
  17. #include <linux/err.h>
  18. #include <linux/irq.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/kernel.h>
  21. #include <linux/module.h>
  22. #include <linux/platform_device.h>
  23. #include <linux/slab.h>
  24. #include <linux/spinlock.h>
  25. #include <linux/clk.h>
  26. #include <linux/mfd/core.h>
  27. #include <linux/jz4740-adc.h>
  28. #define JZ_REG_ADC_ENABLE 0x00
  29. #define JZ_REG_ADC_CFG 0x04
  30. #define JZ_REG_ADC_CTRL 0x08
  31. #define JZ_REG_ADC_STATUS 0x0c
  32. #define JZ_REG_ADC_TOUCHSCREEN_BASE 0x10
  33. #define JZ_REG_ADC_BATTERY_BASE 0x1c
  34. #define JZ_REG_ADC_HWMON_BASE 0x20
  35. #define JZ_ADC_ENABLE_TOUCH BIT(2)
  36. #define JZ_ADC_ENABLE_BATTERY BIT(1)
  37. #define JZ_ADC_ENABLE_ADCIN BIT(0)
  38. enum {
  39. JZ_ADC_IRQ_ADCIN = 0,
  40. JZ_ADC_IRQ_BATTERY,
  41. JZ_ADC_IRQ_TOUCH,
  42. JZ_ADC_IRQ_PENUP,
  43. JZ_ADC_IRQ_PENDOWN,
  44. };
  45. struct jz4740_adc {
  46. struct resource *mem;
  47. void __iomem *base;
  48. int irq;
  49. int irq_base;
  50. struct clk *clk;
  51. atomic_t clk_ref;
  52. spinlock_t lock;
  53. };
  54. static inline void jz4740_adc_irq_set_masked(struct jz4740_adc *adc, int irq,
  55. bool masked)
  56. {
  57. unsigned long flags;
  58. uint8_t val;
  59. irq -= adc->irq_base;
  60. spin_lock_irqsave(&adc->lock, flags);
  61. val = readb(adc->base + JZ_REG_ADC_CTRL);
  62. if (masked)
  63. val |= BIT(irq);
  64. else
  65. val &= ~BIT(irq);
  66. writeb(val, adc->base + JZ_REG_ADC_CTRL);
  67. spin_unlock_irqrestore(&adc->lock, flags);
  68. }
  69. static void jz4740_adc_irq_mask(struct irq_data *data)
  70. {
  71. struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
  72. jz4740_adc_irq_set_masked(adc, data->irq, true);
  73. }
  74. static void jz4740_adc_irq_unmask(struct irq_data *data)
  75. {
  76. struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
  77. jz4740_adc_irq_set_masked(adc, data->irq, false);
  78. }
  79. static void jz4740_adc_irq_ack(struct irq_data *data)
  80. {
  81. struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
  82. unsigned int irq = data->irq - adc->irq_base;
  83. writeb(BIT(irq), adc->base + JZ_REG_ADC_STATUS);
  84. }
  85. static struct irq_chip jz4740_adc_irq_chip = {
  86. .name = "jz4740-adc",
  87. .irq_mask = jz4740_adc_irq_mask,
  88. .irq_unmask = jz4740_adc_irq_unmask,
  89. .irq_ack = jz4740_adc_irq_ack,
  90. };
  91. static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc)
  92. {
  93. struct jz4740_adc *adc = irq_desc_get_handler_data(desc);
  94. uint8_t status;
  95. unsigned int i;
  96. status = readb(adc->base + JZ_REG_ADC_STATUS);
  97. for (i = 0; i < 5; ++i) {
  98. if (status & BIT(i))
  99. generic_handle_irq(adc->irq_base + i);
  100. }
  101. }
  102. /* Refcounting for the ADC clock is done in here instead of in the clock
  103. * framework, because it is the only clock which is shared between multiple
  104. * devices and thus is the only clock which needs refcounting */
  105. static inline void jz4740_adc_clk_enable(struct jz4740_adc *adc)
  106. {
  107. if (atomic_inc_return(&adc->clk_ref) == 1)
  108. clk_enable(adc->clk);
  109. }
  110. static inline void jz4740_adc_clk_disable(struct jz4740_adc *adc)
  111. {
  112. if (atomic_dec_return(&adc->clk_ref) == 0)
  113. clk_disable(adc->clk);
  114. }
  115. static inline void jz4740_adc_set_enabled(struct jz4740_adc *adc, int engine,
  116. bool enabled)
  117. {
  118. unsigned long flags;
  119. uint8_t val;
  120. spin_lock_irqsave(&adc->lock, flags);
  121. val = readb(adc->base + JZ_REG_ADC_ENABLE);
  122. if (enabled)
  123. val |= BIT(engine);
  124. else
  125. val &= ~BIT(engine);
  126. writeb(val, adc->base + JZ_REG_ADC_ENABLE);
  127. spin_unlock_irqrestore(&adc->lock, flags);
  128. }
  129. static int jz4740_adc_cell_enable(struct platform_device *pdev)
  130. {
  131. struct jz4740_adc *adc = dev_get_drvdata(pdev->dev.parent);
  132. jz4740_adc_clk_enable(adc);
  133. jz4740_adc_set_enabled(adc, pdev->id, true);
  134. return 0;
  135. }
  136. static int jz4740_adc_cell_disable(struct platform_device *pdev)
  137. {
  138. struct jz4740_adc *adc = dev_get_drvdata(pdev->dev.parent);
  139. jz4740_adc_set_enabled(adc, pdev->id, false);
  140. jz4740_adc_clk_disable(adc);
  141. return 0;
  142. }
  143. int jz4740_adc_set_config(struct device *dev, uint32_t mask, uint32_t val)
  144. {
  145. struct jz4740_adc *adc = dev_get_drvdata(dev);
  146. unsigned long flags;
  147. uint32_t cfg;
  148. if (!adc)
  149. return -ENODEV;
  150. spin_lock_irqsave(&adc->lock, flags);
  151. cfg = readl(adc->base + JZ_REG_ADC_CFG);
  152. cfg &= ~mask;
  153. cfg |= val;
  154. writel(cfg, adc->base + JZ_REG_ADC_CFG);
  155. spin_unlock_irqrestore(&adc->lock, flags);
  156. return 0;
  157. }
  158. EXPORT_SYMBOL_GPL(jz4740_adc_set_config);
  159. static struct resource jz4740_hwmon_resources[] = {
  160. {
  161. .start = JZ_ADC_IRQ_ADCIN,
  162. .flags = IORESOURCE_IRQ,
  163. },
  164. {
  165. .start = JZ_REG_ADC_HWMON_BASE,
  166. .end = JZ_REG_ADC_HWMON_BASE + 3,
  167. .flags = IORESOURCE_MEM,
  168. },
  169. };
  170. static struct resource jz4740_battery_resources[] = {
  171. {
  172. .start = JZ_ADC_IRQ_BATTERY,
  173. .flags = IORESOURCE_IRQ,
  174. },
  175. {
  176. .start = JZ_REG_ADC_BATTERY_BASE,
  177. .end = JZ_REG_ADC_BATTERY_BASE + 3,
  178. .flags = IORESOURCE_MEM,
  179. },
  180. };
  181. const struct mfd_cell jz4740_adc_cells[] = {
  182. {
  183. .id = 0,
  184. .name = "jz4740-hwmon",
  185. .num_resources = ARRAY_SIZE(jz4740_hwmon_resources),
  186. .resources = jz4740_hwmon_resources,
  187. .enable = jz4740_adc_cell_enable,
  188. .disable = jz4740_adc_cell_disable,
  189. },
  190. {
  191. .id = 1,
  192. .name = "jz4740-battery",
  193. .num_resources = ARRAY_SIZE(jz4740_battery_resources),
  194. .resources = jz4740_battery_resources,
  195. .enable = jz4740_adc_cell_enable,
  196. .disable = jz4740_adc_cell_disable,
  197. },
  198. };
  199. static int __devinit jz4740_adc_probe(struct platform_device *pdev)
  200. {
  201. int ret;
  202. struct jz4740_adc *adc;
  203. struct resource *mem_base;
  204. int irq;
  205. adc = kmalloc(sizeof(*adc), GFP_KERNEL);
  206. if (!adc) {
  207. dev_err(&pdev->dev, "Failed to allocate driver structure\n");
  208. return -ENOMEM;
  209. }
  210. adc->irq = platform_get_irq(pdev, 0);
  211. if (adc->irq < 0) {
  212. ret = adc->irq;
  213. dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
  214. goto err_free;
  215. }
  216. adc->irq_base = platform_get_irq(pdev, 1);
  217. if (adc->irq_base < 0) {
  218. ret = adc->irq_base;
  219. dev_err(&pdev->dev, "Failed to get irq base: %d\n", ret);
  220. goto err_free;
  221. }
  222. mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  223. if (!mem_base) {
  224. ret = -ENOENT;
  225. dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
  226. goto err_free;
  227. }
  228. /* Only request the shared registers for the MFD driver */
  229. adc->mem = request_mem_region(mem_base->start, JZ_REG_ADC_STATUS,
  230. pdev->name);
  231. if (!adc->mem) {
  232. ret = -EBUSY;
  233. dev_err(&pdev->dev, "Failed to request mmio memory region\n");
  234. goto err_free;
  235. }
  236. adc->base = ioremap_nocache(adc->mem->start, resource_size(adc->mem));
  237. if (!adc->base) {
  238. ret = -EBUSY;
  239. dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
  240. goto err_release_mem_region;
  241. }
  242. adc->clk = clk_get(&pdev->dev, "adc");
  243. if (IS_ERR(adc->clk)) {
  244. ret = PTR_ERR(adc->clk);
  245. dev_err(&pdev->dev, "Failed to get clock: %d\n", ret);
  246. goto err_iounmap;
  247. }
  248. spin_lock_init(&adc->lock);
  249. atomic_set(&adc->clk_ref, 0);
  250. platform_set_drvdata(pdev, adc);
  251. for (irq = adc->irq_base; irq < adc->irq_base + 5; ++irq) {
  252. irq_set_chip_data(irq, adc);
  253. irq_set_chip_and_handler(irq, &jz4740_adc_irq_chip,
  254. handle_level_irq);
  255. }
  256. irq_set_handler_data(adc->irq, adc);
  257. irq_set_chained_handler(adc->irq, jz4740_adc_irq_demux);
  258. writeb(0x00, adc->base + JZ_REG_ADC_ENABLE);
  259. writeb(0xff, adc->base + JZ_REG_ADC_CTRL);
  260. ret = mfd_add_devices(&pdev->dev, 0, jz4740_adc_cells,
  261. ARRAY_SIZE(jz4740_adc_cells), mem_base, adc->irq_base);
  262. if (ret < 0)
  263. goto err_clk_put;
  264. return 0;
  265. err_clk_put:
  266. clk_put(adc->clk);
  267. err_iounmap:
  268. platform_set_drvdata(pdev, NULL);
  269. iounmap(adc->base);
  270. err_release_mem_region:
  271. release_mem_region(adc->mem->start, resource_size(adc->mem));
  272. err_free:
  273. kfree(adc);
  274. return ret;
  275. }
  276. static int __devexit jz4740_adc_remove(struct platform_device *pdev)
  277. {
  278. struct jz4740_adc *adc = platform_get_drvdata(pdev);
  279. mfd_remove_devices(&pdev->dev);
  280. irq_set_handler_data(adc->irq, NULL);
  281. irq_set_chained_handler(adc->irq, NULL);
  282. iounmap(adc->base);
  283. release_mem_region(adc->mem->start, resource_size(adc->mem));
  284. clk_put(adc->clk);
  285. platform_set_drvdata(pdev, NULL);
  286. kfree(adc);
  287. return 0;
  288. }
  289. struct platform_driver jz4740_adc_driver = {
  290. .probe = jz4740_adc_probe,
  291. .remove = __devexit_p(jz4740_adc_remove),
  292. .driver = {
  293. .name = "jz4740-adc",
  294. .owner = THIS_MODULE,
  295. },
  296. };
  297. static int __init jz4740_adc_init(void)
  298. {
  299. return platform_driver_register(&jz4740_adc_driver);
  300. }
  301. module_init(jz4740_adc_init);
  302. static void __exit jz4740_adc_exit(void)
  303. {
  304. platform_driver_unregister(&jz4740_adc_driver);
  305. }
  306. module_exit(jz4740_adc_exit);
  307. MODULE_DESCRIPTION("JZ4740 SoC ADC driver");
  308. MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
  309. MODULE_LICENSE("GPL");
  310. MODULE_ALIAS("platform:jz4740-adc");