drivers/iio/adc/mcp3911.c

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

File Facts

System
Linux kernel
Corpus path
drivers/iio/adc/mcp3911.c
Extension
.c
Size
25739 bytes
Lines
956
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 mcp3911_chip_info {
	const struct iio_chan_spec *channels;
	unsigned int num_channels;

	int (*config)(struct mcp3911 *adc, bool external_vref);
	int (*get_osr)(struct mcp3911 *adc, u32 *val);
	int (*set_osr)(struct mcp3911 *adc, u32 val);
	int (*enable_offset)(struct mcp3911 *adc, bool enable);
	int (*get_offset)(struct mcp3911 *adc, int channel, int *val);
	int (*set_offset)(struct mcp3911 *adc, int channel, int val);
	int (*set_scale)(struct mcp3911 *adc, int channel, u32 val);
	int (*get_raw)(struct mcp3911 *adc, int channel, int *val);
};

struct mcp3911 {
	struct spi_device *spi;
	struct mutex lock;
	struct clk *clki;
	u32 dev_addr;
	struct iio_trigger *trig;
	u32 gain[MCP39XX_MAX_NUM_CHANNELS];
	const struct mcp3911_chip_info *chip;
	struct {
		u32 channels[MCP39XX_MAX_NUM_CHANNELS];
		aligned_s64 ts;
	} scan;

	u8 tx_buf __aligned(IIO_DMA_MINALIGN);
	u8 rx_buf[MCP39XX_MAX_NUM_CHANNELS * 3];
};

static int mcp3911_read(struct mcp3911 *adc, u8 reg, u32 *val, u8 len)
{
	int ret;

	reg = MCP3911_REG_READ(reg, adc->dev_addr);
	ret = spi_write_then_read(adc->spi, &reg, 1, val, len);
	if (ret < 0)
		return ret;

	be32_to_cpus(val);
	*val >>= ((4 - len) * 8);
	dev_dbg(&adc->spi->dev, "reading 0x%x from register 0x%lx\n", *val,
		FIELD_GET(MCP3911_REG_MASK, reg));
	return ret;
}

static int mcp3911_write(struct mcp3911 *adc, u8 reg, u32 val, u8 len)
{
	dev_dbg(&adc->spi->dev, "writing 0x%x to register 0x%x\n", val, reg);

	val <<= (3 - len) * 8;
	cpu_to_be32s(&val);
	val |= MCP3911_REG_WRITE(reg, adc->dev_addr);

	return spi_write(adc->spi, &val, len + 1);
}

static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask, u32 val, u8 len)
{
	u32 tmp;
	int ret;

	ret = mcp3911_read(adc, reg, &tmp, len);
	if (ret)
		return ret;

	val &= mask;
	val |= tmp & ~mask;
	return mcp3911_write(adc, reg, val, len);
}

static int mcp3911_read_s24(struct mcp3911 *const adc, u8 const reg, s32 *const val)
{
	u32 uval;
	int const ret = mcp3911_read(adc, reg, &uval, 3);

	if (ret)
		return ret;

	*val = sign_extend32(uval, 23);
	return ret;
}

static int mcp3910_enable_offset(struct mcp3911 *adc, bool enable)
{
	unsigned int mask = MCP3910_CONFIG0_EN_OFFCAL;
	unsigned int value = enable ? mask : 0;

	return mcp3911_update(adc, MCP3910_REG_CONFIG0, mask, value, 3);

Annotation

Implementation Notes