502 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * NXP i.MX8QXP ADC driver4 *5 * Based on the work of Haibo Chen <haibo.chen@nxp.com>6 * The initial developer of the original code is Haibo Chen.7 * Portions created by Haibo Chen are Copyright (C) 2018 NXP.8 * All Rights Reserved.9 *10 * Copyright (C) 2018 NXP11 * Copyright (C) 2021 Cai Huoqing12 */13#include <linux/bitfield.h>14#include <linux/bits.h>15#include <linux/clk.h>16#include <linux/completion.h>17#include <linux/delay.h>18#include <linux/err.h>19#include <linux/interrupt.h>20#include <linux/io.h>21#include <linux/kernel.h>22#include <linux/mod_devicetable.h>23#include <linux/module.h>24#include <linux/platform_device.h>25#include <linux/pm_runtime.h>26#include <linux/regulator/consumer.h>27 28#include <linux/iio/iio.h>29 30#define ADC_DRIVER_NAME "imx8qxp-adc"31 32/* Register map definition */33#define IMX8QXP_ADR_ADC_CTRL 0x1034#define IMX8QXP_ADR_ADC_STAT 0x1435#define IMX8QXP_ADR_ADC_IE 0x1836#define IMX8QXP_ADR_ADC_DE 0x1c37#define IMX8QXP_ADR_ADC_CFG 0x2038#define IMX8QXP_ADR_ADC_FCTRL 0x3039#define IMX8QXP_ADR_ADC_SWTRIG 0x3440#define IMX8QXP_ADR_ADC_TCTRL(tid) (0xc0 + (tid) * 4)41#define IMX8QXP_ADR_ADC_CMDL(cid) (0x100 + (cid) * 8)42#define IMX8QXP_ADR_ADC_CMDH(cid) (0x104 + (cid) * 8)43#define IMX8QXP_ADR_ADC_RESFIFO 0x30044#define IMX8QXP_ADR_ADC_TST 0xffc45 46/* ADC bit shift */47#define IMX8QXP_ADC_IE_FWMIE_MASK GENMASK(1, 0)48#define IMX8QXP_ADC_CTRL_FIFO_RESET_MASK BIT(8)49#define IMX8QXP_ADC_CTRL_SOFTWARE_RESET_MASK BIT(1)50#define IMX8QXP_ADC_CTRL_ADC_EN_MASK BIT(0)51#define IMX8QXP_ADC_TCTRL_TCMD_MASK GENMASK(31, 24)52#define IMX8QXP_ADC_TCTRL_TDLY_MASK GENMASK(23, 16)53#define IMX8QXP_ADC_TCTRL_TPRI_MASK GENMASK(15, 8)54#define IMX8QXP_ADC_TCTRL_HTEN_MASK GENMASK(7, 0)55#define IMX8QXP_ADC_CMDL_CSCALE_MASK GENMASK(13, 8)56#define IMX8QXP_ADC_CMDL_MODE_MASK BIT(7)57#define IMX8QXP_ADC_CMDL_DIFF_MASK BIT(6)58#define IMX8QXP_ADC_CMDL_ABSEL_MASK BIT(5)59#define IMX8QXP_ADC_CMDL_ADCH_MASK GENMASK(2, 0)60#define IMX8QXP_ADC_CMDH_NEXT_MASK GENMASK(31, 24)61#define IMX8QXP_ADC_CMDH_LOOP_MASK GENMASK(23, 16)62#define IMX8QXP_ADC_CMDH_AVGS_MASK GENMASK(15, 12)63#define IMX8QXP_ADC_CMDH_STS_MASK BIT(8)64#define IMX8QXP_ADC_CMDH_LWI_MASK GENMASK(7, 7)65#define IMX8QXP_ADC_CMDH_CMPEN_MASK GENMASK(0, 0)66#define IMX8QXP_ADC_CFG_PWREN_MASK BIT(28)67#define IMX8QXP_ADC_CFG_PUDLY_MASK GENMASK(23, 16)68#define IMX8QXP_ADC_CFG_REFSEL_MASK GENMASK(7, 6)69#define IMX8QXP_ADC_CFG_PWRSEL_MASK GENMASK(5, 4)70#define IMX8QXP_ADC_CFG_TPRICTRL_MASK GENMASK(3, 0)71#define IMX8QXP_ADC_FCTRL_FWMARK_MASK GENMASK(20, 16)72#define IMX8QXP_ADC_FCTRL_FCOUNT_MASK GENMASK(4, 0)73#define IMX8QXP_ADC_RESFIFO_VAL_MASK GENMASK(18, 3)74 75/* ADC PARAMETER*/76#define IMX8QXP_ADC_CMDL_CHANNEL_SCALE_FULL GENMASK(5, 0)77#define IMX8QXP_ADC_CMDL_SEL_A_A_B_CHANNEL 078#define IMX8QXP_ADC_CMDL_STANDARD_RESOLUTION 079#define IMX8QXP_ADC_CMDL_MODE_SINGLE 080#define IMX8QXP_ADC_CMDH_LWI_INCREMENT_DIS 081#define IMX8QXP_ADC_CMDH_CMPEN_DIS 082#define IMX8QXP_ADC_PAUSE_EN BIT(31)83#define IMX8QXP_ADC_TCTRL_TPRI_PRIORITY_HIGH 084 85#define IMX8QXP_ADC_TCTRL_HTEN_HW_TIRG_DIS 086 87#define IMX8QXP_ADC_TIMEOUT msecs_to_jiffies(100)88 89#define IMX8QXP_ADC_MAX_FIFO_SIZE 1690 91struct imx8qxp_adc {92 struct device *dev;93 void __iomem *regs;94 struct clk *clk;95 struct clk *ipg_clk;96 struct regulator *vref;97 /* Serialise ADC channel reads */98 struct mutex lock;99 struct completion completion;100 u32 fifo[IMX8QXP_ADC_MAX_FIFO_SIZE];101};102 103#define IMX8QXP_ADC_CHAN(_idx) { \104 .type = IIO_VOLTAGE, \105 .indexed = 1, \106 .channel = (_idx), \107 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \108 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \109 BIT(IIO_CHAN_INFO_SAMP_FREQ), \110}111 112static const struct iio_chan_spec imx8qxp_adc_iio_channels[] = {113 IMX8QXP_ADC_CHAN(0),114 IMX8QXP_ADC_CHAN(1),115 IMX8QXP_ADC_CHAN(2),116 IMX8QXP_ADC_CHAN(3),117 IMX8QXP_ADC_CHAN(4),118 IMX8QXP_ADC_CHAN(5),119 IMX8QXP_ADC_CHAN(6),120 IMX8QXP_ADC_CHAN(7),121};122 123static void imx8qxp_adc_reset(struct imx8qxp_adc *adc)124{125 u32 ctrl;126 127 /*software reset, need to clear the set bit*/128 ctrl = readl(adc->regs + IMX8QXP_ADR_ADC_CTRL);129 ctrl |= FIELD_PREP(IMX8QXP_ADC_CTRL_SOFTWARE_RESET_MASK, 1);130 writel(ctrl, adc->regs + IMX8QXP_ADR_ADC_CTRL);131 udelay(10);132 ctrl &= ~FIELD_PREP(IMX8QXP_ADC_CTRL_SOFTWARE_RESET_MASK, 1);133 writel(ctrl, adc->regs + IMX8QXP_ADR_ADC_CTRL);134 135 /* reset the fifo */136 ctrl |= FIELD_PREP(IMX8QXP_ADC_CTRL_FIFO_RESET_MASK, 1);137 writel(ctrl, adc->regs + IMX8QXP_ADR_ADC_CTRL);138}139 140static void imx8qxp_adc_reg_config(struct imx8qxp_adc *adc, int channel)141{142 u32 adc_cfg, adc_tctrl, adc_cmdl, adc_cmdh;143 144 /* ADC configuration */145 adc_cfg = FIELD_PREP(IMX8QXP_ADC_CFG_PWREN_MASK, 1) |146 FIELD_PREP(IMX8QXP_ADC_CFG_PUDLY_MASK, 0x80)|147 FIELD_PREP(IMX8QXP_ADC_CFG_REFSEL_MASK, 0) |148 FIELD_PREP(IMX8QXP_ADC_CFG_PWRSEL_MASK, 3) |149 FIELD_PREP(IMX8QXP_ADC_CFG_TPRICTRL_MASK, 0);150 writel(adc_cfg, adc->regs + IMX8QXP_ADR_ADC_CFG);151 152 /* config the trigger control */153 adc_tctrl = FIELD_PREP(IMX8QXP_ADC_TCTRL_TCMD_MASK, 1) |154 FIELD_PREP(IMX8QXP_ADC_TCTRL_TDLY_MASK, 0) |155 FIELD_PREP(IMX8QXP_ADC_TCTRL_TPRI_MASK, IMX8QXP_ADC_TCTRL_TPRI_PRIORITY_HIGH) |156 FIELD_PREP(IMX8QXP_ADC_TCTRL_HTEN_MASK, IMX8QXP_ADC_TCTRL_HTEN_HW_TIRG_DIS);157 writel(adc_tctrl, adc->regs + IMX8QXP_ADR_ADC_TCTRL(0));158 159 /* config the cmd */160 adc_cmdl = FIELD_PREP(IMX8QXP_ADC_CMDL_CSCALE_MASK, IMX8QXP_ADC_CMDL_CHANNEL_SCALE_FULL) |161 FIELD_PREP(IMX8QXP_ADC_CMDL_MODE_MASK, IMX8QXP_ADC_CMDL_STANDARD_RESOLUTION) |162 FIELD_PREP(IMX8QXP_ADC_CMDL_DIFF_MASK, IMX8QXP_ADC_CMDL_MODE_SINGLE) |163 FIELD_PREP(IMX8QXP_ADC_CMDL_ABSEL_MASK, IMX8QXP_ADC_CMDL_SEL_A_A_B_CHANNEL) |164 FIELD_PREP(IMX8QXP_ADC_CMDL_ADCH_MASK, channel);165 writel(adc_cmdl, adc->regs + IMX8QXP_ADR_ADC_CMDL(0));166 167 adc_cmdh = FIELD_PREP(IMX8QXP_ADC_CMDH_NEXT_MASK, 0) |168 FIELD_PREP(IMX8QXP_ADC_CMDH_LOOP_MASK, 0) |169 FIELD_PREP(IMX8QXP_ADC_CMDH_AVGS_MASK, 7) |170 FIELD_PREP(IMX8QXP_ADC_CMDH_STS_MASK, 0) |171 FIELD_PREP(IMX8QXP_ADC_CMDH_LWI_MASK, IMX8QXP_ADC_CMDH_LWI_INCREMENT_DIS) |172 FIELD_PREP(IMX8QXP_ADC_CMDH_CMPEN_MASK, IMX8QXP_ADC_CMDH_CMPEN_DIS);173 writel(adc_cmdh, adc->regs + IMX8QXP_ADR_ADC_CMDH(0));174}175 176static void imx8qxp_adc_fifo_config(struct imx8qxp_adc *adc)177{178 u32 fifo_ctrl, interrupt_en;179 180 fifo_ctrl = readl(adc->regs + IMX8QXP_ADR_ADC_FCTRL);181 fifo_ctrl &= ~IMX8QXP_ADC_FCTRL_FWMARK_MASK;182 /* set the watermark level to 1 */183 fifo_ctrl |= FIELD_PREP(IMX8QXP_ADC_FCTRL_FWMARK_MASK, 0);184 writel(fifo_ctrl, adc->regs + IMX8QXP_ADR_ADC_FCTRL);185 186 /* FIFO Watermark Interrupt Enable */187 interrupt_en = readl(adc->regs + IMX8QXP_ADR_ADC_IE);188 interrupt_en |= FIELD_PREP(IMX8QXP_ADC_IE_FWMIE_MASK, 1);189 writel(interrupt_en, adc->regs + IMX8QXP_ADR_ADC_IE);190}191 192static void imx8qxp_adc_disable(struct imx8qxp_adc *adc)193{194 u32 ctrl;195 196 ctrl = readl(adc->regs + IMX8QXP_ADR_ADC_CTRL);197 ctrl &= ~FIELD_PREP(IMX8QXP_ADC_CTRL_ADC_EN_MASK, 1);198 writel(ctrl, adc->regs + IMX8QXP_ADR_ADC_CTRL);199}200 201static int imx8qxp_adc_read_raw(struct iio_dev *indio_dev,202 struct iio_chan_spec const *chan,203 int *val, int *val2, long mask)204{205 struct imx8qxp_adc *adc = iio_priv(indio_dev);206 struct device *dev = adc->dev;207 208 u32 ctrl;209 long ret;210 211 switch (mask) {212 case IIO_CHAN_INFO_RAW:213 pm_runtime_get_sync(dev);214 215 mutex_lock(&adc->lock);216 reinit_completion(&adc->completion);217 218 imx8qxp_adc_reg_config(adc, chan->channel);219 220 imx8qxp_adc_fifo_config(adc);221 222 /* adc enable */223 ctrl = readl(adc->regs + IMX8QXP_ADR_ADC_CTRL);224 ctrl |= FIELD_PREP(IMX8QXP_ADC_CTRL_ADC_EN_MASK, 1);225 writel(ctrl, adc->regs + IMX8QXP_ADR_ADC_CTRL);226 /* adc start */227 writel(1, adc->regs + IMX8QXP_ADR_ADC_SWTRIG);228 229 ret = wait_for_completion_interruptible_timeout(&adc->completion,230 IMX8QXP_ADC_TIMEOUT);231 232 pm_runtime_mark_last_busy(dev);233 pm_runtime_put_sync_autosuspend(dev);234 235 if (ret == 0) {236 mutex_unlock(&adc->lock);237 return -ETIMEDOUT;238 }239 if (ret < 0) {240 mutex_unlock(&adc->lock);241 return ret;242 }243 244 *val = adc->fifo[0];245 246 mutex_unlock(&adc->lock);247 return IIO_VAL_INT;248 249 case IIO_CHAN_INFO_SCALE:250 ret = regulator_get_voltage(adc->vref);251 if (ret < 0)252 return ret;253 *val = ret / 1000;254 *val2 = 12;255 return IIO_VAL_FRACTIONAL_LOG2;256 257 case IIO_CHAN_INFO_SAMP_FREQ:258 *val = clk_get_rate(adc->clk) / 3;259 return IIO_VAL_INT;260 261 default:262 return -EINVAL;263 }264}265 266static irqreturn_t imx8qxp_adc_isr(int irq, void *dev_id)267{268 struct imx8qxp_adc *adc = dev_id;269 u32 fifo_count;270 int i;271 272 fifo_count = FIELD_GET(IMX8QXP_ADC_FCTRL_FCOUNT_MASK,273 readl(adc->regs + IMX8QXP_ADR_ADC_FCTRL));274 275 for (i = 0; i < fifo_count; i++)276 adc->fifo[i] = FIELD_GET(IMX8QXP_ADC_RESFIFO_VAL_MASK,277 readl_relaxed(adc->regs + IMX8QXP_ADR_ADC_RESFIFO));278 279 if (fifo_count)280 complete(&adc->completion);281 282 return IRQ_HANDLED;283}284 285static int imx8qxp_adc_reg_access(struct iio_dev *indio_dev, unsigned int reg,286 unsigned int writeval, unsigned int *readval)287{288 struct imx8qxp_adc *adc = iio_priv(indio_dev);289 struct device *dev = adc->dev;290 291 if (!readval || reg % 4 || reg > IMX8QXP_ADR_ADC_TST)292 return -EINVAL;293 294 pm_runtime_get_sync(dev);295 296 *readval = readl(adc->regs + reg);297 298 pm_runtime_mark_last_busy(dev);299 pm_runtime_put_sync_autosuspend(dev);300 301 return 0;302}303 304static const struct iio_info imx8qxp_adc_iio_info = {305 .read_raw = &imx8qxp_adc_read_raw,306 .debugfs_reg_access = &imx8qxp_adc_reg_access,307};308 309static int imx8qxp_adc_probe(struct platform_device *pdev)310{311 struct imx8qxp_adc *adc;312 struct iio_dev *indio_dev;313 struct device *dev = &pdev->dev;314 int irq;315 int ret;316 317 indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));318 if (!indio_dev) {319 dev_err(dev, "Failed allocating iio device\n");320 return -ENOMEM;321 }322 323 adc = iio_priv(indio_dev);324 adc->dev = dev;325 326 mutex_init(&adc->lock);327 adc->regs = devm_platform_ioremap_resource(pdev, 0);328 if (IS_ERR(adc->regs))329 return PTR_ERR(adc->regs);330 331 irq = platform_get_irq(pdev, 0);332 if (irq < 0)333 return irq;334 335 adc->clk = devm_clk_get(dev, "per");336 if (IS_ERR(adc->clk))337 return dev_err_probe(dev, PTR_ERR(adc->clk), "Failed getting clock\n");338 339 adc->ipg_clk = devm_clk_get(dev, "ipg");340 if (IS_ERR(adc->ipg_clk))341 return dev_err_probe(dev, PTR_ERR(adc->ipg_clk), "Failed getting clock\n");342 343 adc->vref = devm_regulator_get(dev, "vref");344 if (IS_ERR(adc->vref))345 return dev_err_probe(dev, PTR_ERR(adc->vref), "Failed getting reference voltage\n");346 347 ret = regulator_enable(adc->vref);348 if (ret) {349 dev_err(dev, "Can't enable adc reference top voltage\n");350 return ret;351 }352 353 platform_set_drvdata(pdev, indio_dev);354 355 init_completion(&adc->completion);356 357 indio_dev->name = ADC_DRIVER_NAME;358 indio_dev->info = &imx8qxp_adc_iio_info;359 indio_dev->modes = INDIO_DIRECT_MODE;360 indio_dev->channels = imx8qxp_adc_iio_channels;361 indio_dev->num_channels = ARRAY_SIZE(imx8qxp_adc_iio_channels);362 363 ret = clk_prepare_enable(adc->clk);364 if (ret) {365 dev_err(&pdev->dev, "Could not prepare or enable the clock.\n");366 goto error_regulator_disable;367 }368 369 ret = clk_prepare_enable(adc->ipg_clk);370 if (ret) {371 dev_err(&pdev->dev, "Could not prepare or enable the clock.\n");372 goto error_adc_clk_disable;373 }374 375 ret = devm_request_irq(dev, irq, imx8qxp_adc_isr, 0, ADC_DRIVER_NAME, adc);376 if (ret < 0) {377 dev_err(dev, "Failed requesting irq, irq = %d\n", irq);378 goto error_ipg_clk_disable;379 }380 381 imx8qxp_adc_reset(adc);382 383 ret = iio_device_register(indio_dev);384 if (ret) {385 imx8qxp_adc_disable(adc);386 dev_err(dev, "Couldn't register the device.\n");387 goto error_ipg_clk_disable;388 }389 390 pm_runtime_set_active(dev);391 pm_runtime_set_autosuspend_delay(dev, 50);392 pm_runtime_use_autosuspend(dev);393 pm_runtime_enable(dev);394 395 return 0;396 397error_ipg_clk_disable:398 clk_disable_unprepare(adc->ipg_clk);399error_adc_clk_disable:400 clk_disable_unprepare(adc->clk);401error_regulator_disable:402 regulator_disable(adc->vref);403 404 return ret;405}406 407static void imx8qxp_adc_remove(struct platform_device *pdev)408{409 struct iio_dev *indio_dev = platform_get_drvdata(pdev);410 struct imx8qxp_adc *adc = iio_priv(indio_dev);411 struct device *dev = adc->dev;412 413 pm_runtime_get_sync(dev);414 415 iio_device_unregister(indio_dev);416 417 imx8qxp_adc_disable(adc);418 419 clk_disable_unprepare(adc->clk);420 clk_disable_unprepare(adc->ipg_clk);421 regulator_disable(adc->vref);422 423 pm_runtime_disable(dev);424 pm_runtime_put_noidle(dev);425}426 427static int imx8qxp_adc_runtime_suspend(struct device *dev)428{429 struct iio_dev *indio_dev = dev_get_drvdata(dev);430 struct imx8qxp_adc *adc = iio_priv(indio_dev);431 432 imx8qxp_adc_disable(adc);433 434 clk_disable_unprepare(adc->clk);435 clk_disable_unprepare(adc->ipg_clk);436 regulator_disable(adc->vref);437 438 return 0;439}440 441static int imx8qxp_adc_runtime_resume(struct device *dev)442{443 struct iio_dev *indio_dev = dev_get_drvdata(dev);444 struct imx8qxp_adc *adc = iio_priv(indio_dev);445 int ret;446 447 ret = regulator_enable(adc->vref);448 if (ret) {449 dev_err(dev, "Can't enable adc reference top voltage, err = %d\n", ret);450 return ret;451 }452 453 ret = clk_prepare_enable(adc->clk);454 if (ret) {455 dev_err(dev, "Could not prepare or enable clock.\n");456 goto err_disable_reg;457 }458 459 ret = clk_prepare_enable(adc->ipg_clk);460 if (ret) {461 dev_err(dev, "Could not prepare or enable clock.\n");462 goto err_unprepare_clk;463 }464 465 imx8qxp_adc_reset(adc);466 467 return 0;468 469err_unprepare_clk:470 clk_disable_unprepare(adc->clk);471 472err_disable_reg:473 regulator_disable(adc->vref);474 475 return ret;476}477 478static DEFINE_RUNTIME_DEV_PM_OPS(imx8qxp_adc_pm_ops,479 imx8qxp_adc_runtime_suspend,480 imx8qxp_adc_runtime_resume, NULL);481 482static const struct of_device_id imx8qxp_adc_match[] = {483 { .compatible = "nxp,imx8qxp-adc", },484 { /* sentinel */ }485};486MODULE_DEVICE_TABLE(of, imx8qxp_adc_match);487 488static struct platform_driver imx8qxp_adc_driver = {489 .probe = imx8qxp_adc_probe,490 .remove_new = imx8qxp_adc_remove,491 .driver = {492 .name = ADC_DRIVER_NAME,493 .of_match_table = imx8qxp_adc_match,494 .pm = pm_ptr(&imx8qxp_adc_pm_ops),495 },496};497 498module_platform_driver(imx8qxp_adc_driver);499 500MODULE_DESCRIPTION("i.MX8QuadXPlus ADC driver");501MODULE_LICENSE("GPL v2");502