drivers/iio/magnetometer/tlv493d.c

Source file repositories/reference/linux-study-clean/drivers/iio/magnetometer/tlv493d.c

File Facts

System
Linux kernel
Corpus path
drivers/iio/magnetometer/tlv493d.c
Extension
.c
Size
14633 bytes
Lines
527
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 tlv493d_data {
	struct i2c_client *client;
	/* protects from simultaneous sensor access and register readings */
	struct mutex lock;
	enum tlv493d_op_mode mode;
	u8 wr_regs[TLV493D_WR_REG_MAX];
};

/*
 * Different mode has different measurement sampling time, this time is
 * used in deriving the sleep and timeout while reading the data from
 * sensor in polling.
 * Power-down mode: No measurement.
 * Fast mode: Freq:3.3 KHz. Measurement time:305 usec.
 * Low-power mode: Freq:100 Hz. Measurement time:10 msec.
 * Ultra low-power mode: Freq:10 Hz. Measurement time:100 msec.
 * Master controlled mode: Freq:3.3 Khz. Measurement time:305 usec.
 */
static const u32 tlv493d_sample_rate_us[] = {
	[TLV493D_OP_MODE_POWERDOWN] = 0,
	[TLV493D_OP_MODE_FAST] = 305,
	[TLV493D_OP_MODE_LOWPOWER] = 10 * USEC_PER_MSEC,
	[TLV493D_OP_MODE_ULTRA_LOWPOWER] = 100 * USEC_PER_MSEC,
	[TLV493D_OP_MODE_MASTERCONTROLLED] = 305,
};

static int tlv493d_write_all_regs(struct tlv493d_data *data)
{
	int ret;
	struct device *dev = &data->client->dev;

	ret = i2c_master_send(data->client, data->wr_regs, ARRAY_SIZE(data->wr_regs));
	if (ret < 0) {
		dev_err(dev, "i2c write registers failed, error: %d\n", ret);
		return ret;
	}

	return 0;
}

static int tlv493d_set_operating_mode(struct tlv493d_data *data, enum tlv493d_op_mode mode)
{
	u8 *mode1_cfg = &data->wr_regs[TLV493D_WR_REG_MODE1];
	u8 *mode2_cfg = &data->wr_regs[TLV493D_WR_REG_MODE2];

	switch (mode) {
	case TLV493D_OP_MODE_POWERDOWN:
		FIELD_MODIFY(TLV493D_MODE1_MOD_LOWFAST, mode1_cfg, 0);
		FIELD_MODIFY(TLV493D_MODE2_LP_PERIOD, mode2_cfg, 0);
		break;

	case TLV493D_OP_MODE_FAST:
		FIELD_MODIFY(TLV493D_MODE1_MOD_LOWFAST, mode1_cfg, 1);
		FIELD_MODIFY(TLV493D_MODE2_LP_PERIOD, mode2_cfg, 0);
		break;

	case TLV493D_OP_MODE_LOWPOWER:
		FIELD_MODIFY(TLV493D_MODE1_MOD_LOWFAST, mode1_cfg, 2);
		FIELD_MODIFY(TLV493D_MODE2_LP_PERIOD, mode2_cfg, 1);
		break;

	case TLV493D_OP_MODE_ULTRA_LOWPOWER:
		FIELD_MODIFY(TLV493D_MODE1_MOD_LOWFAST, mode1_cfg, 2);
		FIELD_MODIFY(TLV493D_MODE2_LP_PERIOD, mode2_cfg, 0);
		break;

	case TLV493D_OP_MODE_MASTERCONTROLLED:
		FIELD_MODIFY(TLV493D_MODE1_MOD_LOWFAST, mode1_cfg, 3);
		FIELD_MODIFY(TLV493D_MODE2_LP_PERIOD, mode2_cfg, 0);
		break;
	}

	return tlv493d_write_all_regs(data);
}

static s16 tlv493d_get_channel_data(u8 *b, enum tlv493d_channels ch)
{
	u16 val;

	switch (ch) {
	case TLV493D_AXIS_X:
		val = FIELD_GET(TLV493D_BX_MAG_X_AXIS_MSB, b[TLV493D_RD_REG_BX]) << 4 |
		      FIELD_GET(TLV493D_BX2_MAG_X_AXIS_LSB, b[TLV493D_RD_REG_BX2]);
		break;
	case TLV493D_AXIS_Y:
		val = FIELD_GET(TLV493D_BY_MAG_Y_AXIS_MSB, b[TLV493D_RD_REG_BY]) << 4 |
		      FIELD_GET(TLV493D_BX2_MAG_Y_AXIS_LSB, b[TLV493D_RD_REG_BX2]);
		break;
	case TLV493D_AXIS_Z:
		val = FIELD_GET(TLV493D_BZ_MAG_Z_AXIS_MSB, b[TLV493D_RD_REG_BZ]) << 4 |

Annotation

Implementation Notes