mt6577_auxadc.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /*
  2. * Copyright (c) 2016 MediaTek Inc.
  3. * Author: Zhiyong Tao <zhiyong.tao@mediatek.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include <linux/clk.h>
  15. #include <linux/delay.h>
  16. #include <linux/err.h>
  17. #include <linux/kernel.h>
  18. #include <linux/module.h>
  19. #include <linux/of.h>
  20. #include <linux/of_device.h>
  21. #include <linux/platform_device.h>
  22. #include <linux/iopoll.h>
  23. #include <linux/io.h>
  24. #include <linux/iio/iio.h>
  25. /* Register definitions */
  26. #define MT6577_AUXADC_CON0 0x00
  27. #define MT6577_AUXADC_CON1 0x04
  28. #define MT6577_AUXADC_CON2 0x10
  29. #define MT6577_AUXADC_STA BIT(0)
  30. #define MT6577_AUXADC_DAT0 0x14
  31. #define MT6577_AUXADC_RDY0 BIT(12)
  32. #define MT6577_AUXADC_MISC 0x94
  33. #define MT6577_AUXADC_PDN_EN BIT(14)
  34. #define MT6577_AUXADC_DAT_MASK 0xfff
  35. #define MT6577_AUXADC_SLEEP_US 1000
  36. #define MT6577_AUXADC_TIMEOUT_US 10000
  37. #define MT6577_AUXADC_POWER_READY_MS 1
  38. #define MT6577_AUXADC_SAMPLE_READY_US 25
  39. struct mt6577_auxadc_device {
  40. void __iomem *reg_base;
  41. struct clk *adc_clk;
  42. struct mutex lock;
  43. };
  44. #define MT6577_AUXADC_CHANNEL(idx) { \
  45. .type = IIO_VOLTAGE, \
  46. .indexed = 1, \
  47. .channel = (idx), \
  48. .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
  49. }
  50. static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
  51. MT6577_AUXADC_CHANNEL(0),
  52. MT6577_AUXADC_CHANNEL(1),
  53. MT6577_AUXADC_CHANNEL(2),
  54. MT6577_AUXADC_CHANNEL(3),
  55. MT6577_AUXADC_CHANNEL(4),
  56. MT6577_AUXADC_CHANNEL(5),
  57. MT6577_AUXADC_CHANNEL(6),
  58. MT6577_AUXADC_CHANNEL(7),
  59. MT6577_AUXADC_CHANNEL(8),
  60. MT6577_AUXADC_CHANNEL(9),
  61. MT6577_AUXADC_CHANNEL(10),
  62. MT6577_AUXADC_CHANNEL(11),
  63. MT6577_AUXADC_CHANNEL(12),
  64. MT6577_AUXADC_CHANNEL(13),
  65. MT6577_AUXADC_CHANNEL(14),
  66. MT6577_AUXADC_CHANNEL(15),
  67. };
  68. static inline void mt6577_auxadc_mod_reg(void __iomem *reg,
  69. u32 or_mask, u32 and_mask)
  70. {
  71. u32 val;
  72. val = readl(reg);
  73. val |= or_mask;
  74. val &= ~and_mask;
  75. writel(val, reg);
  76. }
  77. static int mt6577_auxadc_read(struct iio_dev *indio_dev,
  78. struct iio_chan_spec const *chan)
  79. {
  80. u32 val;
  81. void __iomem *reg_channel;
  82. int ret;
  83. struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
  84. reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
  85. chan->channel * 0x04;
  86. mutex_lock(&adc_dev->lock);
  87. mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_CON1,
  88. 0, 1 << chan->channel);
  89. /* read channel and make sure old ready bit == 0 */
  90. ret = readl_poll_timeout(reg_channel, val,
  91. ((val & MT6577_AUXADC_RDY0) == 0),
  92. MT6577_AUXADC_SLEEP_US,
  93. MT6577_AUXADC_TIMEOUT_US);
  94. if (ret < 0) {
  95. dev_err(indio_dev->dev.parent,
  96. "wait for channel[%d] ready bit clear time out\n",
  97. chan->channel);
  98. goto err_timeout;
  99. }
  100. /* set bit to trigger sample */
  101. mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_CON1,
  102. 1 << chan->channel, 0);
  103. /* we must delay here for hardware sample channel data */
  104. udelay(MT6577_AUXADC_SAMPLE_READY_US);
  105. /* check MTK_AUXADC_CON2 if auxadc is idle */
  106. ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val,
  107. ((val & MT6577_AUXADC_STA) == 0),
  108. MT6577_AUXADC_SLEEP_US,
  109. MT6577_AUXADC_TIMEOUT_US);
  110. if (ret < 0) {
  111. dev_err(indio_dev->dev.parent,
  112. "wait for auxadc idle time out\n");
  113. goto err_timeout;
  114. }
  115. /* read channel and make sure ready bit == 1 */
  116. ret = readl_poll_timeout(reg_channel, val,
  117. ((val & MT6577_AUXADC_RDY0) != 0),
  118. MT6577_AUXADC_SLEEP_US,
  119. MT6577_AUXADC_TIMEOUT_US);
  120. if (ret < 0) {
  121. dev_err(indio_dev->dev.parent,
  122. "wait for channel[%d] data ready time out\n",
  123. chan->channel);
  124. goto err_timeout;
  125. }
  126. /* read data */
  127. val = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
  128. mutex_unlock(&adc_dev->lock);
  129. return val;
  130. err_timeout:
  131. mutex_unlock(&adc_dev->lock);
  132. return -ETIMEDOUT;
  133. }
  134. static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
  135. struct iio_chan_spec const *chan,
  136. int *val,
  137. int *val2,
  138. long info)
  139. {
  140. switch (info) {
  141. case IIO_CHAN_INFO_PROCESSED:
  142. *val = mt6577_auxadc_read(indio_dev, chan);
  143. if (*val < 0) {
  144. dev_err(indio_dev->dev.parent,
  145. "failed to sample data on channel[%d]\n",
  146. chan->channel);
  147. return *val;
  148. }
  149. return IIO_VAL_INT;
  150. default:
  151. return -EINVAL;
  152. }
  153. }
  154. static const struct iio_info mt6577_auxadc_info = {
  155. .driver_module = THIS_MODULE,
  156. .read_raw = &mt6577_auxadc_read_raw,
  157. };
  158. static int mt6577_auxadc_probe(struct platform_device *pdev)
  159. {
  160. struct mt6577_auxadc_device *adc_dev;
  161. unsigned long adc_clk_rate;
  162. struct resource *res;
  163. struct iio_dev *indio_dev;
  164. int ret;
  165. indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
  166. if (!indio_dev)
  167. return -ENOMEM;
  168. adc_dev = iio_priv(indio_dev);
  169. indio_dev->dev.parent = &pdev->dev;
  170. indio_dev->name = dev_name(&pdev->dev);
  171. indio_dev->info = &mt6577_auxadc_info;
  172. indio_dev->modes = INDIO_DIRECT_MODE;
  173. indio_dev->channels = mt6577_auxadc_iio_channels;
  174. indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
  175. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  176. adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
  177. if (IS_ERR(adc_dev->reg_base)) {
  178. dev_err(&pdev->dev, "failed to get auxadc base address\n");
  179. return PTR_ERR(adc_dev->reg_base);
  180. }
  181. adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
  182. if (IS_ERR(adc_dev->adc_clk)) {
  183. dev_err(&pdev->dev, "failed to get auxadc clock\n");
  184. return PTR_ERR(adc_dev->adc_clk);
  185. }
  186. ret = clk_prepare_enable(adc_dev->adc_clk);
  187. if (ret) {
  188. dev_err(&pdev->dev, "failed to enable auxadc clock\n");
  189. return ret;
  190. }
  191. adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
  192. if (!adc_clk_rate) {
  193. ret = -EINVAL;
  194. dev_err(&pdev->dev, "null clock rate\n");
  195. goto err_disable_clk;
  196. }
  197. mutex_init(&adc_dev->lock);
  198. mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
  199. MT6577_AUXADC_PDN_EN, 0);
  200. mdelay(MT6577_AUXADC_POWER_READY_MS);
  201. platform_set_drvdata(pdev, indio_dev);
  202. ret = iio_device_register(indio_dev);
  203. if (ret < 0) {
  204. dev_err(&pdev->dev, "failed to register iio device\n");
  205. goto err_power_off;
  206. }
  207. return 0;
  208. err_power_off:
  209. mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
  210. 0, MT6577_AUXADC_PDN_EN);
  211. err_disable_clk:
  212. clk_disable_unprepare(adc_dev->adc_clk);
  213. return ret;
  214. }
  215. static int mt6577_auxadc_remove(struct platform_device *pdev)
  216. {
  217. struct iio_dev *indio_dev = platform_get_drvdata(pdev);
  218. struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
  219. iio_device_unregister(indio_dev);
  220. mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
  221. 0, MT6577_AUXADC_PDN_EN);
  222. clk_disable_unprepare(adc_dev->adc_clk);
  223. return 0;
  224. }
  225. static const struct of_device_id mt6577_auxadc_of_match[] = {
  226. { .compatible = "mediatek,mt2701-auxadc", },
  227. { .compatible = "mediatek,mt8173-auxadc", },
  228. { }
  229. };
  230. MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
  231. static struct platform_driver mt6577_auxadc_driver = {
  232. .driver = {
  233. .name = "mt6577-auxadc",
  234. .of_match_table = mt6577_auxadc_of_match,
  235. },
  236. .probe = mt6577_auxadc_probe,
  237. .remove = mt6577_auxadc_remove,
  238. };
  239. module_platform_driver(mt6577_auxadc_driver);
  240. MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao@mediatek.com>");
  241. MODULE_DESCRIPTION("MTK AUXADC Device Driver");
  242. MODULE_LICENSE("GPL v2");