drivers/iio/adc/adi-axi-adc.c

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

File Facts

System
Linux kernel
Corpus path
drivers/iio/adc/adi-axi-adc.c
Extension
.c
Size
23633 bytes
Lines
814
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 axi_adc_info {
	unsigned int version;
	const struct iio_backend_info *backend_info;
	bool has_child_nodes;
	const void *pdata;
	unsigned int pdata_sz;
};

struct adi_axi_adc_state {
	const struct axi_adc_info *info;
	struct regmap *regmap;
	struct device *dev;
	/* lock to protect multiple accesses to the device registers */
	struct mutex lock;
};

static int axi_adc_enable(struct iio_backend *back)
{
	struct adi_axi_adc_state *st = iio_backend_get_priv(back);
	unsigned int __val;
	int ret;

	guard(mutex)(&st->lock);
	ret = regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN,
			      ADI_AXI_REG_RSTN_MMCM_RSTN);
	if (ret)
		return ret;

	/*
	 * Make sure the DRP (Dynamic Reconfiguration Port) is locked. Not all
	 * designs really use it but if they don't we still get the lock bit
	 * set. So let's do it all the time so the code is generic.
	 */
	ret = regmap_read_poll_timeout(st->regmap, ADI_AXI_ADC_REG_DRP_STATUS,
				       __val, __val & ADI_AXI_ADC_DRP_LOCKED,
				       100, 1000);
	if (ret)
		return ret;

	return regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN,
			       ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN);
}

static void axi_adc_disable(struct iio_backend *back)
{
	struct adi_axi_adc_state *st = iio_backend_get_priv(back);

	guard(mutex)(&st->lock);
	regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0);
}

static int axi_adc_data_format_set(struct iio_backend *back, unsigned int chan,
				   const struct iio_backend_data_fmt *data)
{
	struct adi_axi_adc_state *st = iio_backend_get_priv(back);
	u32 val;

	if (!data->enable)
		return regmap_clear_bits(st->regmap,
					 ADI_AXI_REG_CHAN_CTRL(chan),
					 ADI_AXI_REG_CHAN_CTRL_FMT_EN);

	val = FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_EN, true);
	if (data->sign_extend)
		val |= FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT, true);
	if (data->type == IIO_BACKEND_OFFSET_BINARY)
		val |= FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_TYPE, true);

	return regmap_update_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan),
				  ADI_AXI_REG_CHAN_CTRL_FMT_MASK, val);
}

static int axi_adc_data_sample_trigger(struct iio_backend *back,
				       enum iio_backend_sample_trigger trigger)
{
	struct adi_axi_adc_state *st = iio_backend_get_priv(back);

	switch (trigger) {
	case IIO_BACKEND_SAMPLE_TRIGGER_EDGE_RISING:
		return regmap_clear_bits(st->regmap, ADI_AXI_ADC_REG_CTRL,
					 ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK);
	case IIO_BACKEND_SAMPLE_TRIGGER_EDGE_FALLING:
		return regmap_set_bits(st->regmap, ADI_AXI_ADC_REG_CTRL,
				       ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK);
	default:
		return -EINVAL;
	}
}

static int axi_adc_iodelays_set(struct iio_backend *back, unsigned int lane,

Annotation

Implementation Notes