564 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Freescale i.MX7D ADC driver4 *5 * Copyright (C) 2015 Freescale Semiconductor, Inc.6 */7 8#include <linux/clk.h>9#include <linux/completion.h>10#include <linux/err.h>11#include <linux/interrupt.h>12#include <linux/io.h>13#include <linux/kernel.h>14#include <linux/mod_devicetable.h>15#include <linux/module.h>16#include <linux/mutex.h>17#include <linux/platform_device.h>18#include <linux/regulator/consumer.h>19 20#include <linux/iio/iio.h>21#include <linux/iio/driver.h>22#include <linux/iio/sysfs.h>23 24/* ADC register */25#define IMX7D_REG_ADC_CH_A_CFG1 0x0026#define IMX7D_REG_ADC_CH_A_CFG2 0x1027#define IMX7D_REG_ADC_CH_B_CFG1 0x2028#define IMX7D_REG_ADC_CH_B_CFG2 0x3029#define IMX7D_REG_ADC_CH_C_CFG1 0x4030#define IMX7D_REG_ADC_CH_C_CFG2 0x5031#define IMX7D_REG_ADC_CH_D_CFG1 0x6032#define IMX7D_REG_ADC_CH_D_CFG2 0x7033#define IMX7D_REG_ADC_CH_SW_CFG 0x8034#define IMX7D_REG_ADC_TIMER_UNIT 0x9035#define IMX7D_REG_ADC_DMA_FIFO 0xa036#define IMX7D_REG_ADC_FIFO_STATUS 0xb037#define IMX7D_REG_ADC_INT_SIG_EN 0xc038#define IMX7D_REG_ADC_INT_EN 0xd039#define IMX7D_REG_ADC_INT_STATUS 0xe040#define IMX7D_REG_ADC_CHA_B_CNV_RSLT 0xf041#define IMX7D_REG_ADC_CHC_D_CNV_RSLT 0x10042#define IMX7D_REG_ADC_CH_SW_CNV_RSLT 0x11043#define IMX7D_REG_ADC_DMA_FIFO_DAT 0x12044#define IMX7D_REG_ADC_ADC_CFG 0x13045 46#define IMX7D_REG_ADC_CHANNEL_CFG2_BASE 0x1047#define IMX7D_EACH_CHANNEL_REG_OFFSET 0x2048 49#define IMX7D_REG_ADC_CH_CFG1_CHANNEL_EN (0x1 << 31)50#define IMX7D_REG_ADC_CH_CFG1_CHANNEL_SINGLE BIT(30)51#define IMX7D_REG_ADC_CH_CFG1_CHANNEL_AVG_EN BIT(29)52#define IMX7D_REG_ADC_CH_CFG1_CHANNEL_SEL(x) ((x) << 24)53 54#define IMX7D_REG_ADC_CH_CFG2_AVG_NUM_4 (0x0 << 12)55#define IMX7D_REG_ADC_CH_CFG2_AVG_NUM_8 (0x1 << 12)56#define IMX7D_REG_ADC_CH_CFG2_AVG_NUM_16 (0x2 << 12)57#define IMX7D_REG_ADC_CH_CFG2_AVG_NUM_32 (0x3 << 12)58 59#define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_4 (0x0 << 29)60#define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_8 (0x1 << 29)61#define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_16 (0x2 << 29)62#define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_32 (0x3 << 29)63#define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_64 (0x4 << 29)64#define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_128 (0x5 << 29)65 66#define IMX7D_REG_ADC_ADC_CFG_ADC_CLK_DOWN BIT(31)67#define IMX7D_REG_ADC_ADC_CFG_ADC_POWER_DOWN BIT(1)68#define IMX7D_REG_ADC_ADC_CFG_ADC_EN BIT(0)69 70#define IMX7D_REG_ADC_INT_CHA_COV_INT_EN BIT(8)71#define IMX7D_REG_ADC_INT_CHB_COV_INT_EN BIT(9)72#define IMX7D_REG_ADC_INT_CHC_COV_INT_EN BIT(10)73#define IMX7D_REG_ADC_INT_CHD_COV_INT_EN BIT(11)74#define IMX7D_REG_ADC_INT_CHANNEL_INT_EN \75 (IMX7D_REG_ADC_INT_CHA_COV_INT_EN | \76 IMX7D_REG_ADC_INT_CHB_COV_INT_EN | \77 IMX7D_REG_ADC_INT_CHC_COV_INT_EN | \78 IMX7D_REG_ADC_INT_CHD_COV_INT_EN)79#define IMX7D_REG_ADC_INT_STATUS_CHANNEL_INT_STATUS 0xf0080#define IMX7D_REG_ADC_INT_STATUS_CHANNEL_CONV_TIME_OUT 0xf000081 82#define IMX7D_ADC_TIMEOUT msecs_to_jiffies(100)83#define IMX7D_ADC_INPUT_CLK 2400000084 85enum imx7d_adc_clk_pre_div {86 IMX7D_ADC_ANALOG_CLK_PRE_DIV_4,87 IMX7D_ADC_ANALOG_CLK_PRE_DIV_8,88 IMX7D_ADC_ANALOG_CLK_PRE_DIV_16,89 IMX7D_ADC_ANALOG_CLK_PRE_DIV_32,90 IMX7D_ADC_ANALOG_CLK_PRE_DIV_64,91 IMX7D_ADC_ANALOG_CLK_PRE_DIV_128,92};93 94enum imx7d_adc_average_num {95 IMX7D_ADC_AVERAGE_NUM_4,96 IMX7D_ADC_AVERAGE_NUM_8,97 IMX7D_ADC_AVERAGE_NUM_16,98 IMX7D_ADC_AVERAGE_NUM_32,99};100 101struct imx7d_adc_feature {102 enum imx7d_adc_clk_pre_div clk_pre_div;103 enum imx7d_adc_average_num avg_num;104 105 u32 core_time_unit; /* impact the sample rate */106};107 108struct imx7d_adc {109 struct device *dev;110 void __iomem *regs;111 struct clk *clk;112 /* lock to protect against multiple access to the device */113 struct mutex lock;114 u32 vref_uv;115 u32 value;116 u32 channel;117 u32 pre_div_num;118 119 struct regulator *vref;120 struct imx7d_adc_feature adc_feature;121 122 struct completion completion;123};124 125struct imx7d_adc_analogue_core_clk {126 u32 pre_div;127 u32 reg_config;128};129 130#define IMX7D_ADC_ANALOGUE_CLK_CONFIG(_pre_div, _reg_conf) { \131 .pre_div = (_pre_div), \132 .reg_config = (_reg_conf), \133}134 135static const struct imx7d_adc_analogue_core_clk imx7d_adc_analogue_clk[] = {136 IMX7D_ADC_ANALOGUE_CLK_CONFIG(4, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_4),137 IMX7D_ADC_ANALOGUE_CLK_CONFIG(8, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_8),138 IMX7D_ADC_ANALOGUE_CLK_CONFIG(16, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_16),139 IMX7D_ADC_ANALOGUE_CLK_CONFIG(32, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_32),140 IMX7D_ADC_ANALOGUE_CLK_CONFIG(64, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_64),141 IMX7D_ADC_ANALOGUE_CLK_CONFIG(128, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_128),142};143 144#define IMX7D_ADC_CHAN(_idx) { \145 .type = IIO_VOLTAGE, \146 .indexed = 1, \147 .channel = (_idx), \148 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \149 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \150 BIT(IIO_CHAN_INFO_SAMP_FREQ), \151}152 153static const struct iio_chan_spec imx7d_adc_iio_channels[] = {154 IMX7D_ADC_CHAN(0),155 IMX7D_ADC_CHAN(1),156 IMX7D_ADC_CHAN(2),157 IMX7D_ADC_CHAN(3),158 IMX7D_ADC_CHAN(4),159 IMX7D_ADC_CHAN(5),160 IMX7D_ADC_CHAN(6),161 IMX7D_ADC_CHAN(7),162 IMX7D_ADC_CHAN(8),163 IMX7D_ADC_CHAN(9),164 IMX7D_ADC_CHAN(10),165 IMX7D_ADC_CHAN(11),166 IMX7D_ADC_CHAN(12),167 IMX7D_ADC_CHAN(13),168 IMX7D_ADC_CHAN(14),169 IMX7D_ADC_CHAN(15),170};171 172static const u32 imx7d_adc_average_num[] = {173 IMX7D_REG_ADC_CH_CFG2_AVG_NUM_4,174 IMX7D_REG_ADC_CH_CFG2_AVG_NUM_8,175 IMX7D_REG_ADC_CH_CFG2_AVG_NUM_16,176 IMX7D_REG_ADC_CH_CFG2_AVG_NUM_32,177};178 179static void imx7d_adc_feature_config(struct imx7d_adc *info)180{181 info->adc_feature.clk_pre_div = IMX7D_ADC_ANALOG_CLK_PRE_DIV_4;182 info->adc_feature.avg_num = IMX7D_ADC_AVERAGE_NUM_32;183 info->adc_feature.core_time_unit = 1;184}185 186static void imx7d_adc_sample_rate_set(struct imx7d_adc *info)187{188 struct imx7d_adc_feature *adc_feature = &info->adc_feature;189 struct imx7d_adc_analogue_core_clk adc_analogure_clk;190 u32 i;191 u32 tmp_cfg1;192 u32 sample_rate = 0;193 194 /*195 * Before sample set, disable channel A,B,C,D. Here we196 * clear the bit 31 of register REG_ADC_CH_A\B\C\D_CFG1.197 */198 for (i = 0; i < 4; i++) {199 tmp_cfg1 =200 readl(info->regs + i * IMX7D_EACH_CHANNEL_REG_OFFSET);201 tmp_cfg1 &= ~IMX7D_REG_ADC_CH_CFG1_CHANNEL_EN;202 writel(tmp_cfg1,203 info->regs + i * IMX7D_EACH_CHANNEL_REG_OFFSET);204 }205 206 adc_analogure_clk = imx7d_adc_analogue_clk[adc_feature->clk_pre_div];207 sample_rate |= adc_analogure_clk.reg_config;208 info->pre_div_num = adc_analogure_clk.pre_div;209 210 sample_rate |= adc_feature->core_time_unit;211 writel(sample_rate, info->regs + IMX7D_REG_ADC_TIMER_UNIT);212}213 214static void imx7d_adc_hw_init(struct imx7d_adc *info)215{216 u32 cfg;217 218 /* power up and enable adc analogue core */219 cfg = readl(info->regs + IMX7D_REG_ADC_ADC_CFG);220 cfg &= ~(IMX7D_REG_ADC_ADC_CFG_ADC_CLK_DOWN |221 IMX7D_REG_ADC_ADC_CFG_ADC_POWER_DOWN);222 cfg |= IMX7D_REG_ADC_ADC_CFG_ADC_EN;223 writel(cfg, info->regs + IMX7D_REG_ADC_ADC_CFG);224 225 /* enable channel A,B,C,D interrupt */226 writel(IMX7D_REG_ADC_INT_CHANNEL_INT_EN,227 info->regs + IMX7D_REG_ADC_INT_SIG_EN);228 writel(IMX7D_REG_ADC_INT_CHANNEL_INT_EN,229 info->regs + IMX7D_REG_ADC_INT_EN);230 231 imx7d_adc_sample_rate_set(info);232}233 234static void imx7d_adc_channel_set(struct imx7d_adc *info)235{236 u32 cfg1 = 0;237 u32 cfg2;238 u32 channel;239 240 channel = info->channel;241 242 /* the channel choose single conversion, and enable average mode */243 cfg1 |= (IMX7D_REG_ADC_CH_CFG1_CHANNEL_EN |244 IMX7D_REG_ADC_CH_CFG1_CHANNEL_SINGLE |245 IMX7D_REG_ADC_CH_CFG1_CHANNEL_AVG_EN);246 247 /*248 * physical channel 0 chose logical channel A249 * physical channel 1 chose logical channel B250 * physical channel 2 chose logical channel C251 * physical channel 3 chose logical channel D252 */253 cfg1 |= IMX7D_REG_ADC_CH_CFG1_CHANNEL_SEL(channel);254 255 /*256 * read register REG_ADC_CH_A\B\C\D_CFG2, according to the257 * channel chosen258 */259 cfg2 = readl(info->regs + IMX7D_EACH_CHANNEL_REG_OFFSET * channel +260 IMX7D_REG_ADC_CHANNEL_CFG2_BASE);261 262 cfg2 |= imx7d_adc_average_num[info->adc_feature.avg_num];263 264 /*265 * write the register REG_ADC_CH_A\B\C\D_CFG2, according to266 * the channel chosen267 */268 writel(cfg2, info->regs + IMX7D_EACH_CHANNEL_REG_OFFSET * channel +269 IMX7D_REG_ADC_CHANNEL_CFG2_BASE);270 writel(cfg1, info->regs + IMX7D_EACH_CHANNEL_REG_OFFSET * channel);271}272 273static u32 imx7d_adc_get_sample_rate(struct imx7d_adc *info)274{275 u32 analogue_core_clk;276 u32 core_time_unit = info->adc_feature.core_time_unit;277 u32 tmp;278 279 analogue_core_clk = IMX7D_ADC_INPUT_CLK / info->pre_div_num;280 tmp = (core_time_unit + 1) * 6;281 282 return analogue_core_clk / tmp;283}284 285static int imx7d_adc_read_raw(struct iio_dev *indio_dev,286 struct iio_chan_spec const *chan,287 int *val,288 int *val2,289 long mask)290{291 struct imx7d_adc *info = iio_priv(indio_dev);292 293 u32 channel;294 long ret;295 296 switch (mask) {297 case IIO_CHAN_INFO_RAW:298 mutex_lock(&info->lock);299 reinit_completion(&info->completion);300 301 channel = chan->channel & 0x03;302 info->channel = channel;303 imx7d_adc_channel_set(info);304 305 ret = wait_for_completion_interruptible_timeout306 (&info->completion, IMX7D_ADC_TIMEOUT);307 if (ret == 0) {308 mutex_unlock(&info->lock);309 return -ETIMEDOUT;310 }311 if (ret < 0) {312 mutex_unlock(&info->lock);313 return ret;314 }315 316 *val = info->value;317 mutex_unlock(&info->lock);318 return IIO_VAL_INT;319 320 case IIO_CHAN_INFO_SCALE:321 info->vref_uv = regulator_get_voltage(info->vref);322 *val = info->vref_uv / 1000;323 *val2 = 12;324 return IIO_VAL_FRACTIONAL_LOG2;325 326 case IIO_CHAN_INFO_SAMP_FREQ:327 *val = imx7d_adc_get_sample_rate(info);328 return IIO_VAL_INT;329 330 default:331 return -EINVAL;332 }333}334 335static int imx7d_adc_read_data(struct imx7d_adc *info)336{337 u32 channel;338 u32 value;339 340 channel = info->channel & 0x03;341 342 /*343 * channel A and B conversion result share one register,344 * bit[27~16] is the channel B conversion result,345 * bit[11~0] is the channel A conversion result.346 * channel C and D is the same.347 */348 if (channel < 2)349 value = readl(info->regs + IMX7D_REG_ADC_CHA_B_CNV_RSLT);350 else351 value = readl(info->regs + IMX7D_REG_ADC_CHC_D_CNV_RSLT);352 if (channel & 0x1) /* channel B or D */353 value = (value >> 16) & 0xFFF;354 else /* channel A or C */355 value &= 0xFFF;356 357 return value;358}359 360static irqreturn_t imx7d_adc_isr(int irq, void *dev_id)361{362 struct imx7d_adc *info = dev_id;363 int status;364 365 status = readl(info->regs + IMX7D_REG_ADC_INT_STATUS);366 if (status & IMX7D_REG_ADC_INT_STATUS_CHANNEL_INT_STATUS) {367 info->value = imx7d_adc_read_data(info);368 complete(&info->completion);369 370 /*371 * The register IMX7D_REG_ADC_INT_STATUS can't clear372 * itself after read operation, need software to write373 * 0 to the related bit. Here we clear the channel A/B/C/D374 * conversion finished flag.375 */376 status &= ~IMX7D_REG_ADC_INT_STATUS_CHANNEL_INT_STATUS;377 writel(status, info->regs + IMX7D_REG_ADC_INT_STATUS);378 }379 380 /*381 * If the channel A/B/C/D conversion timeout, report it and clear these382 * timeout flags.383 */384 if (status & IMX7D_REG_ADC_INT_STATUS_CHANNEL_CONV_TIME_OUT) {385 dev_err(info->dev,386 "ADC got conversion time out interrupt: 0x%08x\n",387 status);388 status &= ~IMX7D_REG_ADC_INT_STATUS_CHANNEL_CONV_TIME_OUT;389 writel(status, info->regs + IMX7D_REG_ADC_INT_STATUS);390 }391 392 return IRQ_HANDLED;393}394 395static int imx7d_adc_reg_access(struct iio_dev *indio_dev,396 unsigned reg, unsigned writeval,397 unsigned *readval)398{399 struct imx7d_adc *info = iio_priv(indio_dev);400 401 if (!readval || reg % 4 || reg > IMX7D_REG_ADC_ADC_CFG)402 return -EINVAL;403 404 *readval = readl(info->regs + reg);405 406 return 0;407}408 409static const struct iio_info imx7d_adc_iio_info = {410 .read_raw = &imx7d_adc_read_raw,411 .debugfs_reg_access = &imx7d_adc_reg_access,412};413 414static const struct of_device_id imx7d_adc_match[] = {415 { .compatible = "fsl,imx7d-adc", },416 { /* sentinel */ }417};418MODULE_DEVICE_TABLE(of, imx7d_adc_match);419 420static void imx7d_adc_power_down(struct imx7d_adc *info)421{422 u32 adc_cfg;423 424 adc_cfg = readl(info->regs + IMX7D_REG_ADC_ADC_CFG);425 adc_cfg |= IMX7D_REG_ADC_ADC_CFG_ADC_CLK_DOWN |426 IMX7D_REG_ADC_ADC_CFG_ADC_POWER_DOWN;427 adc_cfg &= ~IMX7D_REG_ADC_ADC_CFG_ADC_EN;428 writel(adc_cfg, info->regs + IMX7D_REG_ADC_ADC_CFG);429}430 431static int imx7d_adc_enable(struct device *dev)432{433 struct iio_dev *indio_dev = dev_get_drvdata(dev);434 struct imx7d_adc *info = iio_priv(indio_dev);435 int ret;436 437 ret = regulator_enable(info->vref);438 if (ret) {439 dev_err(info->dev,440 "Can't enable adc reference top voltage, err = %d\n",441 ret);442 return ret;443 }444 445 ret = clk_prepare_enable(info->clk);446 if (ret) {447 dev_err(info->dev,448 "Could not prepare or enable clock.\n");449 regulator_disable(info->vref);450 return ret;451 }452 453 imx7d_adc_hw_init(info);454 455 return 0;456}457 458static int imx7d_adc_disable(struct device *dev)459{460 struct iio_dev *indio_dev = dev_get_drvdata(dev);461 struct imx7d_adc *info = iio_priv(indio_dev);462 463 imx7d_adc_power_down(info);464 465 clk_disable_unprepare(info->clk);466 regulator_disable(info->vref);467 468 return 0;469}470 471static void __imx7d_adc_disable(void *data)472{473 imx7d_adc_disable(data);474}475 476static int imx7d_adc_probe(struct platform_device *pdev)477{478 struct imx7d_adc *info;479 struct iio_dev *indio_dev;480 struct device *dev = &pdev->dev;481 int irq;482 int ret;483 484 indio_dev = devm_iio_device_alloc(dev, sizeof(*info));485 if (!indio_dev) {486 dev_err(&pdev->dev, "Failed allocating iio device\n");487 return -ENOMEM;488 }489 490 info = iio_priv(indio_dev);491 info->dev = dev;492 493 info->regs = devm_platform_ioremap_resource(pdev, 0);494 if (IS_ERR(info->regs))495 return PTR_ERR(info->regs);496 497 irq = platform_get_irq(pdev, 0);498 if (irq < 0)499 return irq;500 501 info->clk = devm_clk_get(dev, "adc");502 if (IS_ERR(info->clk))503 return dev_err_probe(dev, PTR_ERR(info->clk), "Failed getting clock\n");504 505 info->vref = devm_regulator_get(dev, "vref");506 if (IS_ERR(info->vref))507 return dev_err_probe(dev, PTR_ERR(info->vref),508 "Failed getting reference voltage\n");509 510 platform_set_drvdata(pdev, indio_dev);511 512 init_completion(&info->completion);513 514 indio_dev->name = dev_name(dev);515 indio_dev->info = &imx7d_adc_iio_info;516 indio_dev->modes = INDIO_DIRECT_MODE;517 indio_dev->channels = imx7d_adc_iio_channels;518 indio_dev->num_channels = ARRAY_SIZE(imx7d_adc_iio_channels);519 520 ret = devm_request_irq(dev, irq, imx7d_adc_isr, 0, dev_name(dev), info);521 if (ret < 0) {522 dev_err(dev, "Failed requesting irq, irq = %d\n", irq);523 return ret;524 }525 526 imx7d_adc_feature_config(info);527 528 ret = imx7d_adc_enable(dev);529 if (ret)530 return ret;531 532 ret = devm_add_action_or_reset(dev, __imx7d_adc_disable, dev);533 if (ret)534 return ret;535 536 mutex_init(&info->lock);537 538 ret = devm_iio_device_register(dev, indio_dev);539 if (ret) {540 dev_err(&pdev->dev, "Couldn't register the device.\n");541 return ret;542 }543 544 return 0;545}546 547static DEFINE_SIMPLE_DEV_PM_OPS(imx7d_adc_pm_ops, imx7d_adc_disable,548 imx7d_adc_enable);549 550static struct platform_driver imx7d_adc_driver = {551 .probe = imx7d_adc_probe,552 .driver = {553 .name = "imx7d_adc",554 .of_match_table = imx7d_adc_match,555 .pm = pm_sleep_ptr(&imx7d_adc_pm_ops),556 },557};558 559module_platform_driver(imx7d_adc_driver);560 561MODULE_AUTHOR("Haibo Chen <haibo.chen@freescale.com>");562MODULE_DESCRIPTION("Freescale IMX7D ADC driver");563MODULE_LICENSE("GPL v2");564