brintos

brintos / linux-shallow public Read only

0
0
Text · 13.7 KiB · fe82198 Raw
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