drivers/iio/chemical/sunrise_co2.c

Source file repositories/reference/linux-study-clean/drivers/iio/chemical/sunrise_co2.c

File Facts

System
Linux kernel
Corpus path
drivers/iio/chemical/sunrise_co2.c
Extension
.c
Size
13527 bytes
Lines
536
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 sunrise_dev {
	struct i2c_client *client;
	struct regmap *regmap;
	/* Protects access to IIO attributes. */
	struct mutex lock;
	bool ignore_nak;
};

/* Custom regmap read/write operations: perform unlocked access to the i2c bus. */

static int sunrise_regmap_read(void *context, const void *reg_buf,
			       size_t reg_size, void *val_buf, size_t val_size)
{
	struct i2c_client *client = context;
	struct sunrise_dev *sunrise = i2c_get_clientdata(client);
	union i2c_smbus_data data = { };
	int ret;

	if (reg_size != 1 || !val_size)
		return -EINVAL;

	data.block[0] = val_size;

	/*
	 * Wake up sensor by sending sensor address: START, sensor address,
	 * STOP. Sensor will not ACK this byte.
	 *
	 * The chip enters a low power state after 15ms without
	 * communications or after a complete read/write sequence.
	 */
	__i2c_smbus_xfer(client->adapter, client->addr,
			 sunrise->ignore_nak ? I2C_M_IGNORE_NAK : 0,
			 I2C_SMBUS_WRITE, 0, I2C_SMBUS_BYTE_DATA, &data);

	usleep_range(500, 1500);

	ret = __i2c_smbus_xfer(client->adapter, client->addr, client->flags,
			       I2C_SMBUS_READ, ((u8 *)reg_buf)[0],
			       I2C_SMBUS_I2C_BLOCK_DATA, &data);
	if (ret < 0)
		return ret;

	memcpy(val_buf, &data.block[1], data.block[0]);

	return 0;
}

static int sunrise_regmap_write(void *context, const void *val_buf, size_t count)
{
	struct i2c_client *client = context;
	struct sunrise_dev *sunrise = i2c_get_clientdata(client);
	union i2c_smbus_data data = { };

	/* Discard reg address from values count. */
	if (!count)
		return -EINVAL;
	count--;

	data.block[0] = count;
	memcpy(&data.block[1], (u8 *)val_buf + 1, count);

	__i2c_smbus_xfer(client->adapter, client->addr,
			 sunrise->ignore_nak ? I2C_M_IGNORE_NAK : 0,
			 I2C_SMBUS_WRITE, 0, I2C_SMBUS_BYTE_DATA, &data);

	usleep_range(500, 1500);

	return __i2c_smbus_xfer(client->adapter, client->addr, client->flags,
				I2C_SMBUS_WRITE, ((u8 *)val_buf)[0],
				I2C_SMBUS_I2C_BLOCK_DATA, &data);
}

/*
 * Sunrise i2c read/write operations: lock the i2c segment to avoid losing the
 * wake up session. Use custom regmap operations that perform unlocked access to
 * the i2c bus.
 */
static int sunrise_read_byte(struct sunrise_dev *sunrise, u8 reg)
{
	const struct i2c_client *client = sunrise->client;
	const struct device *dev = &client->dev;
	unsigned int val;
	int ret;

	i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
	ret = regmap_read(sunrise->regmap, reg, &val);
	i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
	if (ret) {
		dev_err(dev, "Read byte failed: reg 0x%02x (%d)\n", reg, ret);
		return ret;

Annotation

Implementation Notes