drivers/hwmon/tmp421.c

Source file repositories/reference/linux-study-clean/drivers/hwmon/tmp421.c

File Facts

System
Linux kernel
Corpus path
drivers/hwmon/tmp421.c
Extension
.c
Size
11330 bytes
Lines
484
Domain
Driver Families
Bucket
drivers/hwmon
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 tmp421_channel {
	const char *label;
	bool enabled;
	s16 temp;
};

struct tmp421_data {
	struct i2c_client *client;
	u32 temp_config[MAX_CHANNELS + 1];
	struct hwmon_channel_info temp_info;
	const struct hwmon_channel_info *info[2];
	struct hwmon_chip_info chip;
	bool valid;
	unsigned long last_updated;
	unsigned long channels;
	u8 config;
	struct tmp421_channel channel[MAX_CHANNELS];
};

static int temp_from_raw(u16 reg, bool extended)
{
	/* Mask out status bits */
	int temp = reg & ~0xf;

	if (extended)
		temp = temp - 64 * 256;
	else
		temp = (s16)temp;

	return DIV_ROUND_CLOSEST(temp * 1000, 256);
}

static int tmp421_update_device(struct tmp421_data *data)
{
	struct i2c_client *client = data->client;
	int ret = 0;
	int i;

	if (time_after(jiffies, data->last_updated + (HZ / 2)) ||
	    !data->valid) {
		data->valid = false;
		ret = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1);
		if (ret < 0)
			return ret;
		data->config = ret;

		for (i = 0; i < data->channels; i++) {
			ret = i2c_smbus_read_byte_data(client, TMP421_TEMP_MSB[i]);
			if (ret < 0)
				return ret;
			data->channel[i].temp = ret << 8;

			ret = i2c_smbus_read_byte_data(client, TMP421_TEMP_LSB[i]);
			if (ret < 0)
				return ret;
			data->channel[i].temp |= ret;
		}
		data->last_updated = jiffies;
		data->valid = true;
	}
	return 0;
}

static int tmp421_enable_channels(struct tmp421_data *data)
{
	int err;
	struct i2c_client *client = data->client;
	struct device *dev = &client->dev;
	int old = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_2);
	int new, i;

	if (old < 0) {
		dev_err(dev, "error reading register, can't disable channels\n");
		return old;
	}

	new = old & ~TMP421_CONFIG_REG_REN_MASK;
	for (i = 0; i < data->channels; i++)
		if (data->channel[i].enabled)
			new |= TMP421_CONFIG_REG_REN(i);

	if (new == old)
		return 0;

	err = i2c_smbus_write_byte_data(client, TMP421_CONFIG_REG_2, new);
	if (err < 0)
		dev_err(dev, "error writing register, can't disable channels\n");

	return err;
}

Annotation

Implementation Notes