mt6577_auxadc.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2016 MediaTek Inc.
  4. * Author: Zhiyong Tao <zhiyong.tao@mediatek.com>
  5. */
  6. #include <linux/clk.h>
  7. #include <linux/delay.h>
  8. #include <linux/err.h>
  9. #include <linux/kernel.h>
  10. #include <linux/module.h>
  11. #include <linux/mod_devicetable.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/property.h>
  14. #include <linux/iopoll.h>
  15. #include <linux/io.h>
  16. #include <linux/iio/iio.h>
  17. /* Register definitions */
  18. #define MT6577_AUXADC_CON0 0x00
  19. #define MT6577_AUXADC_CON1 0x04
  20. #define MT6577_AUXADC_CON2 0x10
  21. #define MT6577_AUXADC_STA BIT(0)
  22. #define MT6577_AUXADC_DAT0 0x14
  23. #define MT6577_AUXADC_RDY0 BIT(12)
  24. #define MT6577_AUXADC_MISC 0x94
  25. #define MT6577_AUXADC_PDN_EN BIT(14)
  26. #define MT6577_AUXADC_DAT_MASK 0xfff
  27. #define MT6577_AUXADC_SLEEP_US 1000
  28. #define MT6577_AUXADC_TIMEOUT_US 10000
  29. #define MT6577_AUXADC_POWER_READY_MS 1
  30. #define MT6577_AUXADC_SAMPLE_READY_US 25
  31. struct mtk_auxadc_compatible {
  32. bool sample_data_cali;
  33. bool check_global_idle;
  34. };
  35. struct mt6577_auxadc_device {
  36. void __iomem *reg_base;
  37. struct clk *adc_clk;
  38. struct mutex lock;
  39. const struct mtk_auxadc_compatible *dev_comp;
  40. };
  41. static const struct mtk_auxadc_compatible mt8173_compat = {
  42. .sample_data_cali = false,
  43. .check_global_idle = true,
  44. };
  45. static const struct mtk_auxadc_compatible mt6765_compat = {
  46. .sample_data_cali = true,
  47. .check_global_idle = false,
  48. };
  49. #define MT6577_AUXADC_CHANNEL(idx) { \
  50. .type = IIO_VOLTAGE, \
  51. .indexed = 1, \
  52. .channel = (idx), \
  53. .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
  54. }
  55. static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
  56. MT6577_AUXADC_CHANNEL(0),
  57. MT6577_AUXADC_CHANNEL(1),
  58. MT6577_AUXADC_CHANNEL(2),
  59. MT6577_AUXADC_CHANNEL(3),
  60. MT6577_AUXADC_CHANNEL(4),
  61. MT6577_AUXADC_CHANNEL(5),
  62. MT6577_AUXADC_CHANNEL(6),
  63. MT6577_AUXADC_CHANNEL(7),
  64. MT6577_AUXADC_CHANNEL(8),
  65. MT6577_AUXADC_CHANNEL(9),
  66. MT6577_AUXADC_CHANNEL(10),
  67. MT6577_AUXADC_CHANNEL(11),
  68. MT6577_AUXADC_CHANNEL(12),
  69. MT6577_AUXADC_CHANNEL(13),
  70. MT6577_AUXADC_CHANNEL(14),
  71. MT6577_AUXADC_CHANNEL(15),
  72. };
  73. /* For Voltage calculation */
  74. #define VOLTAGE_FULL_RANGE 1500 /* VA voltage */
  75. #define AUXADC_PRECISE 4096 /* 12 bits */
  76. static int mt_auxadc_get_cali_data(int rawdata, bool enable_cali)
  77. {
  78. return rawdata;
  79. }
  80. static inline void mt6577_auxadc_mod_reg(void __iomem *reg,
  81. u32 or_mask, u32 and_mask)
  82. {
  83. u32 val;
  84. val = readl(reg);
  85. val |= or_mask;
  86. val &= ~and_mask;
  87. writel(val, reg);
  88. }
  89. static int mt6577_auxadc_read(struct iio_dev *indio_dev,
  90. struct iio_chan_spec const *chan)
  91. {
  92. u32 val;
  93. void __iomem *reg_channel;
  94. int ret;
  95. struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
  96. reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
  97. chan->channel * 0x04;
  98. mutex_lock(&adc_dev->lock);
  99. mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_CON1,
  100. 0, 1 << chan->channel);
  101. /* read channel and make sure old ready bit == 0 */
  102. ret = readl_poll_timeout(reg_channel, val,
  103. ((val & MT6577_AUXADC_RDY0) == 0),
  104. MT6577_AUXADC_SLEEP_US,
  105. MT6577_AUXADC_TIMEOUT_US);
  106. if (ret < 0) {
  107. dev_err(indio_dev->dev.parent,
  108. "wait for channel[%d] ready bit clear time out\n",
  109. chan->channel);
  110. goto err_timeout;
  111. }
  112. /* set bit to trigger sample */
  113. mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_CON1,
  114. 1 << chan->channel, 0);
  115. /* we must delay here for hardware sample channel data */
  116. udelay(MT6577_AUXADC_SAMPLE_READY_US);
  117. if (adc_dev->dev_comp->check_global_idle) {
  118. /* check MTK_AUXADC_CON2 if auxadc is idle */
  119. ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2,
  120. val, ((val & MT6577_AUXADC_STA) == 0),
  121. MT6577_AUXADC_SLEEP_US,
  122. MT6577_AUXADC_TIMEOUT_US);
  123. if (ret < 0) {
  124. dev_err(indio_dev->dev.parent,
  125. "wait for auxadc idle time out\n");
  126. goto err_timeout;
  127. }
  128. }
  129. /* read channel and make sure ready bit == 1 */
  130. ret = readl_poll_timeout(reg_channel, val,
  131. ((val & MT6577_AUXADC_RDY0) != 0),
  132. MT6577_AUXADC_SLEEP_US,
  133. MT6577_AUXADC_TIMEOUT_US);
  134. if (ret < 0) {
  135. dev_err(indio_dev->dev.parent,
  136. "wait for channel[%d] data ready time out\n",
  137. chan->channel);
  138. goto err_timeout;
  139. }
  140. /* read data */
  141. val = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
  142. mutex_unlock(&adc_dev->lock);
  143. return val;
  144. err_timeout:
  145. mutex_unlock(&adc_dev->lock);
  146. return -ETIMEDOUT;
  147. }
  148. static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
  149. struct iio_chan_spec const *chan,
  150. int *val,
  151. int *val2,
  152. long info)
  153. {
  154. struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
  155. switch (info) {
  156. case IIO_CHAN_INFO_PROCESSED:
  157. *val = mt6577_auxadc_read(indio_dev, chan);
  158. if (*val < 0) {
  159. dev_err(indio_dev->dev.parent,
  160. "failed to sample data on channel[%d]\n",
  161. chan->channel);
  162. return *val;
  163. }
  164. if (adc_dev->dev_comp->sample_data_cali)
  165. *val = mt_auxadc_get_cali_data(*val, true);
  166. /* Convert adc raw data to voltage: 0 - 1500 mV */
  167. *val = *val * VOLTAGE_FULL_RANGE / AUXADC_PRECISE;
  168. return IIO_VAL_INT;
  169. default:
  170. return -EINVAL;
  171. }
  172. }
  173. static const struct iio_info mt6577_auxadc_info = {
  174. .read_raw = &mt6577_auxadc_read_raw,
  175. };
  176. static int __maybe_unused mt6577_auxadc_resume(struct device *dev)
  177. {
  178. struct iio_dev *indio_dev = dev_get_drvdata(dev);
  179. struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
  180. int ret;
  181. ret = clk_prepare_enable(adc_dev->adc_clk);
  182. if (ret) {
  183. pr_err("failed to enable auxadc clock\n");
  184. return ret;
  185. }
  186. mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
  187. MT6577_AUXADC_PDN_EN, 0);
  188. mdelay(MT6577_AUXADC_POWER_READY_MS);
  189. return 0;
  190. }
  191. static int __maybe_unused mt6577_auxadc_suspend(struct device *dev)
  192. {
  193. struct iio_dev *indio_dev = dev_get_drvdata(dev);
  194. struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
  195. mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
  196. 0, MT6577_AUXADC_PDN_EN);
  197. clk_disable_unprepare(adc_dev->adc_clk);
  198. return 0;
  199. }
  200. static int mt6577_auxadc_probe(struct platform_device *pdev)
  201. {
  202. struct mt6577_auxadc_device *adc_dev;
  203. unsigned long adc_clk_rate;
  204. struct iio_dev *indio_dev;
  205. int ret;
  206. indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
  207. if (!indio_dev)
  208. return -ENOMEM;
  209. adc_dev = iio_priv(indio_dev);
  210. indio_dev->name = dev_name(&pdev->dev);
  211. indio_dev->info = &mt6577_auxadc_info;
  212. indio_dev->modes = INDIO_DIRECT_MODE;
  213. indio_dev->channels = mt6577_auxadc_iio_channels;
  214. indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
  215. adc_dev->reg_base = devm_platform_ioremap_resource(pdev, 0);
  216. if (IS_ERR(adc_dev->reg_base)) {
  217. dev_err(&pdev->dev, "failed to get auxadc base address\n");
  218. return PTR_ERR(adc_dev->reg_base);
  219. }
  220. adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
  221. if (IS_ERR(adc_dev->adc_clk)) {
  222. dev_err(&pdev->dev, "failed to get auxadc clock\n");
  223. return PTR_ERR(adc_dev->adc_clk);
  224. }
  225. ret = clk_prepare_enable(adc_dev->adc_clk);
  226. if (ret) {
  227. dev_err(&pdev->dev, "failed to enable auxadc clock\n");
  228. return ret;
  229. }
  230. adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
  231. if (!adc_clk_rate) {
  232. ret = -EINVAL;
  233. dev_err(&pdev->dev, "null clock rate\n");
  234. goto err_disable_clk;
  235. }
  236. adc_dev->dev_comp = device_get_match_data(&pdev->dev);
  237. mutex_init(&adc_dev->lock);
  238. mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
  239. MT6577_AUXADC_PDN_EN, 0);
  240. mdelay(MT6577_AUXADC_POWER_READY_MS);
  241. platform_set_drvdata(pdev, indio_dev);
  242. ret = iio_device_register(indio_dev);
  243. if (ret < 0) {
  244. dev_err(&pdev->dev, "failed to register iio device\n");
  245. goto err_power_off;
  246. }
  247. return 0;
  248. err_power_off:
  249. mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
  250. 0, MT6577_AUXADC_PDN_EN);
  251. err_disable_clk:
  252. clk_disable_unprepare(adc_dev->adc_clk);
  253. return ret;
  254. }
  255. static int mt6577_auxadc_remove(struct platform_device *pdev)
  256. {
  257. struct iio_dev *indio_dev = platform_get_drvdata(pdev);
  258. struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
  259. iio_device_unregister(indio_dev);
  260. mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
  261. 0, MT6577_AUXADC_PDN_EN);
  262. clk_disable_unprepare(adc_dev->adc_clk);
  263. return 0;
  264. }
  265. static SIMPLE_DEV_PM_OPS(mt6577_auxadc_pm_ops,
  266. mt6577_auxadc_suspend,
  267. mt6577_auxadc_resume);
  268. static const struct of_device_id mt6577_auxadc_of_match[] = {
  269. { .compatible = "mediatek,mt2701-auxadc", .data = &mt8173_compat},
  270. { .compatible = "mediatek,mt2712-auxadc", .data = &mt8173_compat},
  271. { .compatible = "mediatek,mt7622-auxadc", .data = &mt8173_compat},
  272. { .compatible = "mediatek,mt8173-auxadc", .data = &mt8173_compat},
  273. { .compatible = "mediatek,mt6765-auxadc", .data = &mt6765_compat},
  274. { }
  275. };
  276. MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
  277. static struct platform_driver mt6577_auxadc_driver = {
  278. .driver = {
  279. .name = "mt6577-auxadc",
  280. .of_match_table = mt6577_auxadc_of_match,
  281. .pm = &mt6577_auxadc_pm_ops,
  282. },
  283. .probe = mt6577_auxadc_probe,
  284. .remove = mt6577_auxadc_remove,
  285. };
  286. module_platform_driver(mt6577_auxadc_driver);
  287. MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao@mediatek.com>");
  288. MODULE_DESCRIPTION("MTK AUXADC Device Driver");
  289. MODULE_LICENSE("GPL v2");