drivers/iio/adc/fsl-imx25-gcq.c

Source file repositories/reference/linux-study-clean/drivers/iio/adc/fsl-imx25-gcq.c

File Facts

System
Linux kernel
Corpus path
drivers/iio/adc/fsl-imx25-gcq.c
Extension
.c
Size
9880 bytes
Lines
391
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 mx25_gcq_priv {
	struct regmap *regs;
	struct completion completed;
	struct clk *clk;
	int irq;
	struct regulator *vref[4];
	u32 channel_vref_mv[MX25_NUM_CFGS];
	/*
	 * 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;
};

#define MX25_CQG_CHAN(chan, id) {\
	.type = IIO_VOLTAGE,\
	.indexed = 1,\
	.channel = chan,\
	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
			      BIT(IIO_CHAN_INFO_SCALE),\
	.datasheet_name = id,\
}

static const struct iio_chan_spec mx25_gcq_channels[MX25_NUM_CFGS] = {
	MX25_CQG_CHAN(MX25_CFG_XP, "xp"),
	MX25_CQG_CHAN(MX25_CFG_YP, "yp"),
	MX25_CQG_CHAN(MX25_CFG_XN, "xn"),
	MX25_CQG_CHAN(MX25_CFG_YN, "yn"),
	MX25_CQG_CHAN(MX25_CFG_WIPER, "wiper"),
	MX25_CQG_CHAN(MX25_CFG_INAUX0, "inaux0"),
	MX25_CQG_CHAN(MX25_CFG_INAUX1, "inaux1"),
	MX25_CQG_CHAN(MX25_CFG_INAUX2, "inaux2"),
};

static const char * const mx25_gcq_refp_names[] = {
	[MX25_ADC_REFP_YP] = "yp",
	[MX25_ADC_REFP_XP] = "xp",
	[MX25_ADC_REFP_INT] = "int",
	[MX25_ADC_REFP_EXT] = "ext",
};

static irqreturn_t mx25_gcq_irq(int irq, void *data)
{
	struct mx25_gcq_priv *priv = data;
	u32 stats;

	regmap_read(priv->regs, MX25_ADCQ_SR, &stats);

	if (stats & MX25_ADCQ_SR_EOQ) {
		regmap_set_bits(priv->regs, MX25_ADCQ_MR,
				MX25_ADCQ_MR_EOQ_IRQ);
		complete(&priv->completed);
	}

	/* Disable conversion queue run */
	regmap_clear_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS);

	/* Acknowledge all possible irqs */
	regmap_write(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_FRR |
		     MX25_ADCQ_SR_FUR | MX25_ADCQ_SR_FOR |
		     MX25_ADCQ_SR_EOQ | MX25_ADCQ_SR_PD);

	return IRQ_HANDLED;
}

static int mx25_gcq_get_raw_value(struct device *dev,
				  struct iio_chan_spec const *chan,
				  struct mx25_gcq_priv *priv,
				  int *val)
{
	long time_left;
	u32 data;

	/* Setup the configuration we want to use */
	regmap_write(priv->regs, MX25_ADCQ_ITEM_7_0,
		     MX25_ADCQ_ITEM(0, chan->channel));

	regmap_clear_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_EOQ_IRQ);

	/* Trigger queue for one run */
	regmap_set_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS);

	time_left = wait_for_completion_interruptible_timeout(
		&priv->completed, MX25_GCQ_TIMEOUT);
	if (time_left < 0) {
		dev_err(dev, "ADC wait for measurement failed\n");

Annotation

Implementation Notes