drivers/iio/dac/ltc2688.c

Source file repositories/reference/linux-study-clean/drivers/iio/dac/ltc2688.c

File Facts

System
Linux kernel
Corpus path
drivers/iio/dac/ltc2688.c
Extension
.c
Size
26408 bytes
Lines
1013
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 ltc2688_chan {
	long dither_frequency[LTC2688_DITHER_FREQ_AVAIL_N];
	bool overrange;
	bool toggle_chan;
	u8 mode;
};

struct ltc2688_state {
	struct spi_device *spi;
	struct regmap *regmap;
	struct ltc2688_chan channels[LTC2688_DAC_CHANNELS];
	struct iio_chan_spec *iio_chan;
	/* lock to protect against multiple access to the device and shared data */
	struct mutex lock;
	int vref;
	/*
	 * DMA (thus cache coherency maintenance) may require the
	 * transfer buffers to live in their own cache lines.
	 */
	u8 tx_data[6] __aligned(IIO_DMA_MINALIGN);
	u8 rx_data[3];
};

static int ltc2688_spi_read(void *context, const void *reg, size_t reg_size,
			    void *val, size_t val_size)
{
	struct ltc2688_state *st = context;
	struct spi_transfer xfers[] = {
		{
			.tx_buf = st->tx_data,
			.len = reg_size + val_size,
			.cs_change = 1,
		}, {
			.tx_buf = st->tx_data + 3,
			.rx_buf = st->rx_data,
			.len = reg_size + val_size,
		},
	};
	int ret;

	memcpy(st->tx_data, reg, reg_size);

	ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
	if (ret)
		return ret;

	memcpy(val, &st->rx_data[1], val_size);

	return 0;
}

static int ltc2688_spi_write(void *context, const void *data, size_t count)
{
	struct ltc2688_state *st = context;

	return spi_write(st->spi, data, count);
}

static int ltc2688_span_get(const struct ltc2688_state *st, int c)
{
	int ret, reg, span;

	ret = regmap_read(st->regmap, LTC2688_CMD_CH_SETTING(c), &reg);
	if (ret)
		return ret;

	span = FIELD_GET(LTC2688_CH_SPAN_MSK, reg);
	/* sanity check to make sure we don't get any weird value from the HW */
	if (span >= LTC2688_SPAN_RANGE_MAX)
		return -EIO;

	return span;
}

static const int ltc2688_span_helper[LTC2688_SPAN_RANGE_MAX][2] = {
	{0, 5000}, {0, 10000}, {-5000, 5000}, {-10000, 10000}, {-15000, 15000},
};

static int ltc2688_scale_get(const struct ltc2688_state *st, int c, int *val)
{
	const struct ltc2688_chan *chan = &st->channels[c];
	int span, fs;

	span = ltc2688_span_get(st, c);
	if (span < 0)
		return span;

	fs = ltc2688_span_helper[span][1] - ltc2688_span_helper[span][0];
	if (chan->overrange)
		fs = mult_frac(fs, 105, 100);

Annotation

Implementation Notes