drivers/iio/adc/dln2-adc.c

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

File Facts

System
Linux kernel
Corpus path
drivers/iio/adc/dln2-adc.c
Extension
.c
Size
17048 bytes
Lines
689
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 dln2_adc_demux_table {
	unsigned int from;
	unsigned int to;
	unsigned int length;
};

struct dln2_adc {
	struct platform_device *pdev;
	struct iio_chan_spec iio_channels[DLN2_ADC_MAX_CHANNELS + 1];
	int port, trigger_chan;
	struct iio_trigger *trig;
	struct mutex mutex;
	/* Cached sample period in milliseconds */
	unsigned int sample_period;
	/* Demux table */
	unsigned int demux_count;
	struct dln2_adc_demux_table demux[DLN2_ADC_MAX_CHANNELS];
};

struct dln2_adc_port_chan {
	u8 port;
	u8 chan;
};

struct dln2_adc_get_all_vals {
	__le16 channel_mask;
	__le16 values[DLN2_ADC_MAX_CHANNELS];
};

static void dln2_adc_add_demux(struct dln2_adc *dln2,
	unsigned int in_loc, unsigned int out_loc,
	unsigned int length)
{
	struct dln2_adc_demux_table *p = dln2->demux_count ?
		&dln2->demux[dln2->demux_count - 1] : NULL;

	if (p && p->from + p->length == in_loc &&
		p->to + p->length == out_loc) {
		p->length += length;
	} else if (dln2->demux_count < DLN2_ADC_MAX_CHANNELS) {
		p = &dln2->demux[dln2->demux_count++];
		p->from = in_loc;
		p->to = out_loc;
		p->length = length;
	}
}

static void dln2_adc_update_demux(struct dln2_adc *dln2)
{
	int in_ind = -1, out_ind;
	unsigned int in_loc = 0, out_loc = 0;
	struct iio_dev *indio_dev = platform_get_drvdata(dln2->pdev);

	/* Clear out any old demux */
	dln2->demux_count = 0;

	/* Optimize all 8-channels case */
	if (iio_get_masklength(indio_dev) &&
	    (*indio_dev->active_scan_mask & 0xff) == 0xff) {
		dln2_adc_add_demux(dln2, 0, 0, 16);
		return;
	}

	/* Build demux table from fixed 8-channels to active_scan_mask */
	iio_for_each_active_channel(indio_dev, out_ind) {
		/* Handle timestamp separately */
		if (out_ind == DLN2_ADC_MAX_CHANNELS)
			break;
		for (++in_ind; in_ind != out_ind; ++in_ind)
			in_loc += 2;
		dln2_adc_add_demux(dln2, in_loc, out_loc, 2);
		out_loc += 2;
		in_loc += 2;
	}
}

static int dln2_adc_get_chan_count(struct dln2_adc *dln2)
{
	int ret;
	u8 port = dln2->port;
	u8 count;
	int olen = sizeof(count);

	ret = dln2_transfer(dln2->pdev, DLN2_ADC_GET_CHANNEL_COUNT,
			    &port, sizeof(port), &count, &olen);
	if (ret < 0) {
		dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
		return ret;
	}
	if (olen < sizeof(count))

Annotation

Implementation Notes