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