drivers/iio/amplifiers/ada4250.c

Source file repositories/reference/linux-study-clean/drivers/iio/amplifiers/ada4250.c

File Facts

System
Linux kernel
Corpus path
drivers/iio/amplifiers/ada4250.c
Extension
.c
Size
9766 bytes
Lines
385
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 ada4250_state {
	struct spi_device	*spi;
	struct regmap		*regmap;
	/* Protect against concurrent accesses to the device and data content */
	struct mutex		lock;
	int			avdd_uv;
	int			offset_uv;
	u8			bias;
	u8			gain;
	bool			refbuf_en;
	__le16			reg_val_16 __aligned(IIO_DMA_MINALIGN);
};

/* ADA4250 Current Bias Source Settings: Disabled, Bandgap Reference, AVDD */
static const int calibbias_table[] = {0, 1, 2};

/* ADA4250 Gain (V/V) values: 1, 2, 4, 8, 16, 32, 64, 128 */
static const int hwgain_table[] = {1, 2, 4, 8, 16, 32, 64, 128};

static const struct regmap_config ada4250_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
	.read_flag_mask = BIT(7),
	.max_register = 0x1A,
};

static int ada4250_set_offset_uv(struct iio_dev *indio_dev,
				 const struct iio_chan_spec *chan,
				 int offset_uv)
{
	struct ada4250_state *st = iio_priv(indio_dev);

	int i, ret, x[8], max_vos, min_vos, voltage_v, vlsb = 0;
	u8 offset_raw, range = ADA4250_RANGE1;
	u32 lsb_coeff[6] = {1333, 2301, 4283, 8289, 16311, 31599};

	if (st->bias == 0 || st->bias == 3)
		return -EINVAL;

	voltage_v = DIV_ROUND_CLOSEST(st->avdd_uv, MICRO);

	if (st->bias == ADA4250_BIAS_AVDD)
		x[0] = voltage_v;
	else
		x[0] = 5;

	x[1] = 126 * (x[0] - 1);

	for (i = 0; i < 6; i++)
		x[i + 2] = DIV_ROUND_CLOSEST(x[1] * 1000, lsb_coeff[i]);

	if (st->gain == 0)
		return -EINVAL;

	/*
	 * Compute Range and Voltage per LSB for the Sensor Offset Calibration
	 * Example of computation for Range 1 and Range 2 (Current Bias Set = AVDD):
	 *                     Range 1                            Range 2
	 *   Gain   | Max Vos(mV) |   LSB(mV)        |  Max Vos(mV)  | LSB(mV) |
	 *    2     |    X1*127   | X1=0.126(AVDD-1) |   X1*3*127    |  X1*3   |
	 *    4     |    X2*127   | X2=X1/1.3333     |   X2*3*127    |  X2*3   |
	 *    8     |    X3*127   | X3=X1/2.301      |   X3*3*127    |  X3*3   |
	 *    16    |    X4*127   | X4=X1/4.283      |   X4*3*127    |  X4*3   |
	 *    32    |    X5*127   | X5=X1/8.289      |   X5*3*127    |  X5*3   |
	 *    64    |    X6*127   | X6=X1/16.311     |   X6*3*127    |  X6*3   |
	 *    128   |    X7*127   | X7=X1/31.599     |   X7*3*127    |  X7*3   |
	 */
	for (i = ADA4250_RANGE1; i <= ADA4250_RANGE4; i++) {
		max_vos = x[st->gain] *  127 * ((1 << (i + 1)) - 1);
		min_vos = -1 * max_vos;
		if (offset_uv > min_vos && offset_uv < max_vos) {
			range = i;
			vlsb = x[st->gain] * ((1 << (i + 1)) - 1);
			break;
		}
	}

	if (vlsb <= 0)
		return -EINVAL;

	offset_raw = DIV_ROUND_CLOSEST(abs(offset_uv), vlsb);

	mutex_lock(&st->lock);
	ret = regmap_update_bits(st->regmap, ADA4250_REG_SNSR_CAL_CNFG,
				 ADA4250_RANGE_SET_MSK,
				 FIELD_PREP(ADA4250_RANGE_SET_MSK, range));
	if (ret)
		goto exit;

	st->offset_uv = offset_raw * vlsb;

Annotation

Implementation Notes