drivers/iio/adc/ingenic-adc.c

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

File Facts

System
Linux kernel
Corpus path
drivers/iio/adc/ingenic-adc.c
Extension
.c
Size
24576 bytes
Lines
925
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 ingenic_adc_soc_data {
	unsigned int battery_high_vref;
	unsigned int battery_high_vref_bits;
	const int *battery_raw_avail;
	size_t battery_raw_avail_size;
	const int *battery_scale_avail;
	size_t battery_scale_avail_size;
	unsigned int battery_vref_mode: 1;
	unsigned int has_aux_md: 1;
	const struct iio_chan_spec *channels;
	unsigned int num_channels;
	int (*init_clk_div)(struct device *dev, struct ingenic_adc *adc);
};

struct ingenic_adc {
	void __iomem *base;
	struct clk *clk;
	struct mutex lock;
	struct mutex aux_lock;
	const struct ingenic_adc_soc_data *soc_data;
	bool low_vref_mode;
};

static void ingenic_adc_set_adcmd(struct iio_dev *iio_dev, unsigned long mask)
{
	struct ingenic_adc *adc = iio_priv(iio_dev);

	mutex_lock(&adc->lock);

	/* Init ADCMD */
	readl(adc->base + JZ_ADC_REG_ADCMD);

	if (mask & 0x3) {
		/* Second channel (INGENIC_ADC_TOUCH_YP): sample YP vs. GND */
		writel(JZ_ADC_REG_ADCMD_XNGRU
		       | JZ_ADC_REG_ADCMD_VREFNXN | JZ_ADC_REG_ADCMD_VREFPVDD33
		       | JZ_ADC_REG_ADCMD_YPADC,
		       adc->base + JZ_ADC_REG_ADCMD);

		/* First channel (INGENIC_ADC_TOUCH_XP): sample XP vs. GND */
		writel(JZ_ADC_REG_ADCMD_YNGRU
		       | JZ_ADC_REG_ADCMD_VREFNYN | JZ_ADC_REG_ADCMD_VREFPVDD33
		       | JZ_ADC_REG_ADCMD_XPADC,
		       adc->base + JZ_ADC_REG_ADCMD);
	}

	if (mask & 0xc) {
		/* Fourth channel (INGENIC_ADC_TOUCH_YN): sample YN vs. GND */
		writel(JZ_ADC_REG_ADCMD_XNGRU
		       | JZ_ADC_REG_ADCMD_VREFNXN | JZ_ADC_REG_ADCMD_VREFPVDD33
		       | JZ_ADC_REG_ADCMD_YNADC,
		       adc->base + JZ_ADC_REG_ADCMD);

		/* Third channel (INGENIC_ADC_TOUCH_XN): sample XN vs. GND */
		writel(JZ_ADC_REG_ADCMD_YNGRU
		       | JZ_ADC_REG_ADCMD_VREFNYN | JZ_ADC_REG_ADCMD_VREFPVDD33
		       | JZ_ADC_REG_ADCMD_XNADC,
		       adc->base + JZ_ADC_REG_ADCMD);
	}

	if (mask & 0x30) {
		/* Sixth channel (INGENIC_ADC_TOUCH_YD): sample YP vs. YN */
		writel(JZ_ADC_REG_ADCMD_VREFNYN | JZ_ADC_REG_ADCMD_VREFPVDD33
		       | JZ_ADC_REG_ADCMD_YPADC,
		       adc->base + JZ_ADC_REG_ADCMD);

		/* Fifth channel (INGENIC_ADC_TOUCH_XD): sample XP vs. XN */
		writel(JZ_ADC_REG_ADCMD_VREFNXN | JZ_ADC_REG_ADCMD_VREFPVDD33
		       | JZ_ADC_REG_ADCMD_XPADC,
		       adc->base + JZ_ADC_REG_ADCMD);
	}

	/* We're done */
	writel(0, adc->base + JZ_ADC_REG_ADCMD);

	mutex_unlock(&adc->lock);
}

static void ingenic_adc_set_config(struct ingenic_adc *adc,
				   uint32_t mask,
				   uint32_t val)
{
	uint32_t cfg;

	mutex_lock(&adc->lock);

	cfg = readl(adc->base + JZ_ADC_REG_CFG) & ~mask;
	cfg |= val;
	writel(cfg, adc->base + JZ_ADC_REG_CFG);

Annotation

Implementation Notes