drivers/iio/adc/imx8qxp-adc.c

Source file repositories/reference/linux-study-clean/drivers/iio/adc/imx8qxp-adc.c

File Facts

System
Linux kernel
Corpus path
drivers/iio/adc/imx8qxp-adc.c
Extension
.c
Size
13875 bytes
Lines
498
Domain
Driver Families
Bucket
drivers/iio
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct imx8qxp_adc {
	struct device *dev;
	void __iomem *regs;
	struct clk *clk;
	struct clk *ipg_clk;
	struct regulator *vref;
	/* Serialise ADC channel reads */
	struct mutex lock;
	struct completion completion;
	u32 fifo[IMX8QXP_ADC_MAX_FIFO_SIZE];
};

#define IMX8QXP_ADC_CHAN(_idx) {				\
	.type = IIO_VOLTAGE,					\
	.indexed = 1,						\
	.channel = (_idx),					\
	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\
				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
}

static const struct iio_chan_spec imx8qxp_adc_iio_channels[] = {
	IMX8QXP_ADC_CHAN(0),
	IMX8QXP_ADC_CHAN(1),
	IMX8QXP_ADC_CHAN(2),
	IMX8QXP_ADC_CHAN(3),
	IMX8QXP_ADC_CHAN(4),
	IMX8QXP_ADC_CHAN(5),
	IMX8QXP_ADC_CHAN(6),
	IMX8QXP_ADC_CHAN(7),
};

static void imx8qxp_adc_reset(struct imx8qxp_adc *adc)
{
	u32 ctrl;

	/*software reset, need to clear the set bit*/
	ctrl = readl(adc->regs + IMX8QXP_ADR_ADC_CTRL);
	ctrl |= FIELD_PREP(IMX8QXP_ADC_CTRL_SOFTWARE_RESET_MASK, 1);
	writel(ctrl, adc->regs + IMX8QXP_ADR_ADC_CTRL);
	udelay(10);
	ctrl &= ~FIELD_PREP(IMX8QXP_ADC_CTRL_SOFTWARE_RESET_MASK, 1);
	writel(ctrl, adc->regs + IMX8QXP_ADR_ADC_CTRL);

	/* reset the fifo */
	ctrl |= FIELD_PREP(IMX8QXP_ADC_CTRL_FIFO_RESET_MASK, 1);
	writel(ctrl, adc->regs + IMX8QXP_ADR_ADC_CTRL);
}

static void imx8qxp_adc_reg_config(struct imx8qxp_adc *adc, int channel)
{
	u32 adc_cfg, adc_tctrl, adc_cmdl, adc_cmdh;

	/* ADC configuration */
	adc_cfg = FIELD_PREP(IMX8QXP_ADC_CFG_PWREN_MASK, 1) |
		  FIELD_PREP(IMX8QXP_ADC_CFG_PUDLY_MASK, 0x80)|
		  FIELD_PREP(IMX8QXP_ADC_CFG_REFSEL_MASK, 0) |
		  FIELD_PREP(IMX8QXP_ADC_CFG_PWRSEL_MASK, 3) |
		  FIELD_PREP(IMX8QXP_ADC_CFG_TPRICTRL_MASK, 0);
	writel(adc_cfg, adc->regs + IMX8QXP_ADR_ADC_CFG);

	/* config the trigger control */
	adc_tctrl = FIELD_PREP(IMX8QXP_ADC_TCTRL_TCMD_MASK, 1) |
		    FIELD_PREP(IMX8QXP_ADC_TCTRL_TDLY_MASK, 0) |
		    FIELD_PREP(IMX8QXP_ADC_TCTRL_TPRI_MASK, IMX8QXP_ADC_TCTRL_TPRI_PRIORITY_HIGH) |
		    FIELD_PREP(IMX8QXP_ADC_TCTRL_HTEN_MASK, IMX8QXP_ADC_TCTRL_HTEN_HW_TIRG_DIS);
	writel(adc_tctrl, adc->regs + IMX8QXP_ADR_ADC_TCTRL(0));

	/* config the cmd */
	adc_cmdl = FIELD_PREP(IMX8QXP_ADC_CMDL_CSCALE_MASK, IMX8QXP_ADC_CMDL_CHANNEL_SCALE_FULL) |
		   FIELD_PREP(IMX8QXP_ADC_CMDL_MODE_MASK, IMX8QXP_ADC_CMDL_STANDARD_RESOLUTION) |
		   FIELD_PREP(IMX8QXP_ADC_CMDL_DIFF_MASK, IMX8QXP_ADC_CMDL_MODE_SINGLE) |
		   FIELD_PREP(IMX8QXP_ADC_CMDL_ABSEL_MASK, IMX8QXP_ADC_CMDL_SEL_A_A_B_CHANNEL) |
		   FIELD_PREP(IMX8QXP_ADC_CMDL_ADCH_MASK, channel);
	writel(adc_cmdl, adc->regs + IMX8QXP_ADR_ADC_CMDL(0));

	adc_cmdh = FIELD_PREP(IMX8QXP_ADC_CMDH_NEXT_MASK, 0) |
		   FIELD_PREP(IMX8QXP_ADC_CMDH_LOOP_MASK, 0) |
		   FIELD_PREP(IMX8QXP_ADC_CMDH_AVGS_MASK, 7) |
		   FIELD_PREP(IMX8QXP_ADC_CMDH_STS_MASK, 0) |
		   FIELD_PREP(IMX8QXP_ADC_CMDH_LWI_MASK, IMX8QXP_ADC_CMDH_LWI_INCREMENT_DIS) |
		   FIELD_PREP(IMX8QXP_ADC_CMDH_CMPEN_MASK, IMX8QXP_ADC_CMDH_CMPEN_DIS);
	writel(adc_cmdh, adc->regs + IMX8QXP_ADR_ADC_CMDH(0));
}

static void imx8qxp_adc_fifo_config(struct imx8qxp_adc *adc)
{
	u32 fifo_ctrl, interrupt_en;

	fifo_ctrl = readl(adc->regs + IMX8QXP_ADR_ADC_FCTRL);

Annotation

Implementation Notes