Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2016 MediaTek Inc.
0004  * Author: Zhiyong Tao <zhiyong.tao@mediatek.com>
0005  */
0006 
0007 #include <linux/clk.h>
0008 #include <linux/delay.h>
0009 #include <linux/err.h>
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/mod_devicetable.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/property.h>
0015 #include <linux/iopoll.h>
0016 #include <linux/io.h>
0017 #include <linux/iio/iio.h>
0018 
0019 /* Register definitions */
0020 #define MT6577_AUXADC_CON0                    0x00
0021 #define MT6577_AUXADC_CON1                    0x04
0022 #define MT6577_AUXADC_CON2                    0x10
0023 #define MT6577_AUXADC_STA                     BIT(0)
0024 
0025 #define MT6577_AUXADC_DAT0                    0x14
0026 #define MT6577_AUXADC_RDY0                    BIT(12)
0027 
0028 #define MT6577_AUXADC_MISC                    0x94
0029 #define MT6577_AUXADC_PDN_EN                  BIT(14)
0030 
0031 #define MT6577_AUXADC_DAT_MASK                0xfff
0032 #define MT6577_AUXADC_SLEEP_US                1000
0033 #define MT6577_AUXADC_TIMEOUT_US              10000
0034 #define MT6577_AUXADC_POWER_READY_MS          1
0035 #define MT6577_AUXADC_SAMPLE_READY_US         25
0036 
0037 struct mtk_auxadc_compatible {
0038     bool sample_data_cali;
0039     bool check_global_idle;
0040 };
0041 
0042 struct mt6577_auxadc_device {
0043     void __iomem *reg_base;
0044     struct clk *adc_clk;
0045     struct mutex lock;
0046     const struct mtk_auxadc_compatible *dev_comp;
0047 };
0048 
0049 static const struct mtk_auxadc_compatible mt8186_compat = {
0050     .sample_data_cali = false,
0051     .check_global_idle = false,
0052 };
0053 
0054 static const struct mtk_auxadc_compatible mt8173_compat = {
0055     .sample_data_cali = false,
0056     .check_global_idle = true,
0057 };
0058 
0059 static const struct mtk_auxadc_compatible mt6765_compat = {
0060     .sample_data_cali = true,
0061     .check_global_idle = false,
0062 };
0063 
0064 #define MT6577_AUXADC_CHANNEL(idx) {                    \
0065         .type = IIO_VOLTAGE,                    \
0066         .indexed = 1,                       \
0067         .channel = (idx),                   \
0068         .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
0069 }
0070 
0071 static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
0072     MT6577_AUXADC_CHANNEL(0),
0073     MT6577_AUXADC_CHANNEL(1),
0074     MT6577_AUXADC_CHANNEL(2),
0075     MT6577_AUXADC_CHANNEL(3),
0076     MT6577_AUXADC_CHANNEL(4),
0077     MT6577_AUXADC_CHANNEL(5),
0078     MT6577_AUXADC_CHANNEL(6),
0079     MT6577_AUXADC_CHANNEL(7),
0080     MT6577_AUXADC_CHANNEL(8),
0081     MT6577_AUXADC_CHANNEL(9),
0082     MT6577_AUXADC_CHANNEL(10),
0083     MT6577_AUXADC_CHANNEL(11),
0084     MT6577_AUXADC_CHANNEL(12),
0085     MT6577_AUXADC_CHANNEL(13),
0086     MT6577_AUXADC_CHANNEL(14),
0087     MT6577_AUXADC_CHANNEL(15),
0088 };
0089 
0090 /* For Voltage calculation */
0091 #define VOLTAGE_FULL_RANGE  1500    /* VA voltage */
0092 #define AUXADC_PRECISE      4096    /* 12 bits */
0093 
0094 static int mt_auxadc_get_cali_data(int rawdata, bool enable_cali)
0095 {
0096     return rawdata;
0097 }
0098 
0099 static inline void mt6577_auxadc_mod_reg(void __iomem *reg,
0100                      u32 or_mask, u32 and_mask)
0101 {
0102     u32 val;
0103 
0104     val = readl(reg);
0105     val |= or_mask;
0106     val &= ~and_mask;
0107     writel(val, reg);
0108 }
0109 
0110 static int mt6577_auxadc_read(struct iio_dev *indio_dev,
0111                   struct iio_chan_spec const *chan)
0112 {
0113     u32 val;
0114     void __iomem *reg_channel;
0115     int ret;
0116     struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
0117 
0118     reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
0119               chan->channel * 0x04;
0120 
0121     mutex_lock(&adc_dev->lock);
0122 
0123     mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_CON1,
0124                   0, 1 << chan->channel);
0125 
0126     /* read channel and make sure old ready bit == 0 */
0127     ret = readl_poll_timeout(reg_channel, val,
0128                  ((val & MT6577_AUXADC_RDY0) == 0),
0129                  MT6577_AUXADC_SLEEP_US,
0130                  MT6577_AUXADC_TIMEOUT_US);
0131     if (ret < 0) {
0132         dev_err(indio_dev->dev.parent,
0133             "wait for channel[%d] ready bit clear time out\n",
0134             chan->channel);
0135         goto err_timeout;
0136     }
0137 
0138     /* set bit to trigger sample */
0139     mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_CON1,
0140                   1 << chan->channel, 0);
0141 
0142     /* we must delay here for hardware sample channel data */
0143     udelay(MT6577_AUXADC_SAMPLE_READY_US);
0144 
0145     if (adc_dev->dev_comp->check_global_idle) {
0146         /* check MTK_AUXADC_CON2 if auxadc is idle */
0147         ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2,
0148                      val, ((val & MT6577_AUXADC_STA) == 0),
0149                      MT6577_AUXADC_SLEEP_US,
0150                      MT6577_AUXADC_TIMEOUT_US);
0151         if (ret < 0) {
0152             dev_err(indio_dev->dev.parent,
0153                 "wait for auxadc idle time out\n");
0154             goto err_timeout;
0155         }
0156     }
0157 
0158     /* read channel and make sure ready bit == 1 */
0159     ret = readl_poll_timeout(reg_channel, val,
0160                  ((val & MT6577_AUXADC_RDY0) != 0),
0161                  MT6577_AUXADC_SLEEP_US,
0162                  MT6577_AUXADC_TIMEOUT_US);
0163     if (ret < 0) {
0164         dev_err(indio_dev->dev.parent,
0165             "wait for channel[%d] data ready time out\n",
0166             chan->channel);
0167         goto err_timeout;
0168     }
0169 
0170     /* read data */
0171     val = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
0172 
0173     mutex_unlock(&adc_dev->lock);
0174 
0175     return val;
0176 
0177 err_timeout:
0178 
0179     mutex_unlock(&adc_dev->lock);
0180 
0181     return -ETIMEDOUT;
0182 }
0183 
0184 static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
0185                   struct iio_chan_spec const *chan,
0186                   int *val,
0187                   int *val2,
0188                   long info)
0189 {
0190     struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
0191 
0192     switch (info) {
0193     case IIO_CHAN_INFO_PROCESSED:
0194         *val = mt6577_auxadc_read(indio_dev, chan);
0195         if (*val < 0) {
0196             dev_err(indio_dev->dev.parent,
0197                 "failed to sample data on channel[%d]\n",
0198                 chan->channel);
0199             return *val;
0200         }
0201         if (adc_dev->dev_comp->sample_data_cali)
0202             *val = mt_auxadc_get_cali_data(*val, true);
0203 
0204         /* Convert adc raw data to voltage: 0 - 1500 mV */
0205         *val = *val * VOLTAGE_FULL_RANGE / AUXADC_PRECISE;
0206 
0207         return IIO_VAL_INT;
0208 
0209     default:
0210         return -EINVAL;
0211     }
0212 }
0213 
0214 static const struct iio_info mt6577_auxadc_info = {
0215     .read_raw = &mt6577_auxadc_read_raw,
0216 };
0217 
0218 static int mt6577_auxadc_resume(struct device *dev)
0219 {
0220     struct iio_dev *indio_dev = dev_get_drvdata(dev);
0221     struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
0222     int ret;
0223 
0224     ret = clk_prepare_enable(adc_dev->adc_clk);
0225     if (ret) {
0226         pr_err("failed to enable auxadc clock\n");
0227         return ret;
0228     }
0229 
0230     mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
0231                   MT6577_AUXADC_PDN_EN, 0);
0232     mdelay(MT6577_AUXADC_POWER_READY_MS);
0233 
0234     return 0;
0235 }
0236 
0237 static int mt6577_auxadc_suspend(struct device *dev)
0238 {
0239     struct iio_dev *indio_dev = dev_get_drvdata(dev);
0240     struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
0241 
0242     mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
0243                   0, MT6577_AUXADC_PDN_EN);
0244     clk_disable_unprepare(adc_dev->adc_clk);
0245 
0246     return 0;
0247 }
0248 
0249 static int mt6577_auxadc_probe(struct platform_device *pdev)
0250 {
0251     struct mt6577_auxadc_device *adc_dev;
0252     unsigned long adc_clk_rate;
0253     struct iio_dev *indio_dev;
0254     int ret;
0255 
0256     indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
0257     if (!indio_dev)
0258         return -ENOMEM;
0259 
0260     adc_dev = iio_priv(indio_dev);
0261     indio_dev->name = dev_name(&pdev->dev);
0262     indio_dev->info = &mt6577_auxadc_info;
0263     indio_dev->modes = INDIO_DIRECT_MODE;
0264     indio_dev->channels = mt6577_auxadc_iio_channels;
0265     indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
0266 
0267     adc_dev->reg_base = devm_platform_ioremap_resource(pdev, 0);
0268     if (IS_ERR(adc_dev->reg_base)) {
0269         dev_err(&pdev->dev, "failed to get auxadc base address\n");
0270         return PTR_ERR(adc_dev->reg_base);
0271     }
0272 
0273     adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
0274     if (IS_ERR(adc_dev->adc_clk)) {
0275         dev_err(&pdev->dev, "failed to get auxadc clock\n");
0276         return PTR_ERR(adc_dev->adc_clk);
0277     }
0278 
0279     ret = clk_prepare_enable(adc_dev->adc_clk);
0280     if (ret) {
0281         dev_err(&pdev->dev, "failed to enable auxadc clock\n");
0282         return ret;
0283     }
0284 
0285     adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
0286     if (!adc_clk_rate) {
0287         ret = -EINVAL;
0288         dev_err(&pdev->dev, "null clock rate\n");
0289         goto err_disable_clk;
0290     }
0291 
0292     adc_dev->dev_comp = device_get_match_data(&pdev->dev);
0293 
0294     mutex_init(&adc_dev->lock);
0295 
0296     mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
0297                   MT6577_AUXADC_PDN_EN, 0);
0298     mdelay(MT6577_AUXADC_POWER_READY_MS);
0299 
0300     platform_set_drvdata(pdev, indio_dev);
0301 
0302     ret = iio_device_register(indio_dev);
0303     if (ret < 0) {
0304         dev_err(&pdev->dev, "failed to register iio device\n");
0305         goto err_power_off;
0306     }
0307 
0308     return 0;
0309 
0310 err_power_off:
0311     mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
0312                   0, MT6577_AUXADC_PDN_EN);
0313 err_disable_clk:
0314     clk_disable_unprepare(adc_dev->adc_clk);
0315     return ret;
0316 }
0317 
0318 static int mt6577_auxadc_remove(struct platform_device *pdev)
0319 {
0320     struct iio_dev *indio_dev = platform_get_drvdata(pdev);
0321     struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
0322 
0323     iio_device_unregister(indio_dev);
0324 
0325     mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
0326                   0, MT6577_AUXADC_PDN_EN);
0327 
0328     clk_disable_unprepare(adc_dev->adc_clk);
0329 
0330     return 0;
0331 }
0332 
0333 static DEFINE_SIMPLE_DEV_PM_OPS(mt6577_auxadc_pm_ops,
0334                 mt6577_auxadc_suspend,
0335                 mt6577_auxadc_resume);
0336 
0337 static const struct of_device_id mt6577_auxadc_of_match[] = {
0338     { .compatible = "mediatek,mt2701-auxadc", .data = &mt8173_compat },
0339     { .compatible = "mediatek,mt2712-auxadc", .data = &mt8173_compat },
0340     { .compatible = "mediatek,mt7622-auxadc", .data = &mt8173_compat },
0341     { .compatible = "mediatek,mt8173-auxadc", .data = &mt8173_compat },
0342     { .compatible = "mediatek,mt8186-auxadc", .data = &mt8186_compat },
0343     { .compatible = "mediatek,mt6765-auxadc", .data = &mt6765_compat },
0344     { }
0345 };
0346 MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
0347 
0348 static struct platform_driver mt6577_auxadc_driver = {
0349     .driver = {
0350         .name   = "mt6577-auxadc",
0351         .of_match_table = mt6577_auxadc_of_match,
0352         .pm = pm_sleep_ptr(&mt6577_auxadc_pm_ops),
0353     },
0354     .probe  = mt6577_auxadc_probe,
0355     .remove = mt6577_auxadc_remove,
0356 };
0357 module_platform_driver(mt6577_auxadc_driver);
0358 
0359 MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao@mediatek.com>");
0360 MODULE_DESCRIPTION("MTK AUXADC Device Driver");
0361 MODULE_LICENSE("GPL v2");