drivers/iio/adc/sun20i-gpadc-iio.c

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

File Facts

System
Linux kernel
Corpus path
drivers/iio/adc/sun20i-gpadc-iio.c
Extension
.c
Size
7231 bytes
Lines
263
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 sun20i_gpadc_iio {
	void __iomem		*regs;
	struct completion	completion;
	int			last_channel;
	/*
	 * Lock to protect the device state during a potential concurrent
	 * read access from userspace. Reading a raw value requires a sequence
	 * of register writes, then a wait for a completion callback,
	 * and finally a register read, during which userspace could issue
	 * another read request. This lock protects a read access from
	 * occurring before another one has finished.
	 */
	struct mutex		lock;
};

static int sun20i_gpadc_adc_read(struct sun20i_gpadc_iio *info,
				 struct iio_chan_spec const *chan, int *val)
{
	u32 ctrl;
	int ret = IIO_VAL_INT;

	mutex_lock(&info->lock);

	reinit_completion(&info->completion);

	if (info->last_channel != chan->channel) {
		info->last_channel = chan->channel;

		/* enable the analog input channel */
		writel(SUN20I_GPADC_CS_EN_ADC_CH(chan->channel),
		       info->regs + SUN20I_GPADC_CS_EN);

		/* enable the data irq for input channel */
		writel(SUN20I_GPADC_DATA_INTC_CH_DATA_IRQ_EN(chan->channel),
		       info->regs + SUN20I_GPADC_DATA_INTC);
	}

	/* enable the ADC function */
	ctrl = readl(info->regs + SUN20I_GPADC_CTRL);
	ctrl |= FIELD_PREP(SUN20I_GPADC_CTRL_ADC_EN_MASK, 1);
	writel(ctrl, info->regs + SUN20I_GPADC_CTRL);

	/*
	 * According to the datasheet maximum acquire time(TACQ) can be
	 * (65535+1)/24Mhz and conversion time(CONV_TIME) is always constant
	 * and equal to 14/24Mhz, so (TACQ+CONV_TIME) <= 2.73125ms.
	 * A 10ms delay should be enough to make sure an interrupt occurs in
	 * normal conditions. If it doesn't occur, then there is a timeout.
	 */
	if (!wait_for_completion_timeout(&info->completion, msecs_to_jiffies(10))) {
		ret = -ETIMEDOUT;
		goto err_unlock;
	}

	/* read the ADC data */
	*val = readl(info->regs + SUN20I_GPADC_CH_DATA(chan->channel));

err_unlock:
	mutex_unlock(&info->lock);

	return ret;
}

static int sun20i_gpadc_read_raw(struct iio_dev *indio_dev,
				 struct iio_chan_spec const *chan, int *val,
				 int *val2, long mask)
{
	struct sun20i_gpadc_iio *info = iio_priv(indio_dev);

	switch (mask) {
	case IIO_CHAN_INFO_RAW:
		return sun20i_gpadc_adc_read(info, chan, val);
	case IIO_CHAN_INFO_SCALE:
		/* value in mv = 1800mV / 4096 raw */
		*val = 1800;
		*val2 = 12;
		return IIO_VAL_FRACTIONAL_LOG2;
	default:
		return -EINVAL;
	}
}

static irqreturn_t sun20i_gpadc_irq_handler(int irq, void *data)
{
	struct sun20i_gpadc_iio *info = data;

	/* clear data interrupt status register */
	writel(GENMASK(31, 0), info->regs + SUN20I_GPADC_DATA_INTS);

	complete(&info->completion);

Annotation

Implementation Notes