drivers/hwmon/tmp464.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hwmon/tmp464.c
Extension
.c
Size
18517 bytes
Lines
693
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 tmp464_channel {
	const char *label;
	bool enabled;
};

struct tmp464_data {
	struct regmap *regmap;
	int channels;
	s16 config_orig;
	u16 open_reg;
	unsigned long last_updated;
	bool valid;
	int update_interval;
	struct tmp464_channel channel[MAX_CHANNELS];
};

static int temp_from_reg(s16 reg)
{
	return DIV_ROUND_CLOSEST((reg >> 3) * 625, 10);
}

static s16 temp_to_limit_reg(long temp)
{
	return DIV_ROUND_CLOSEST(temp, 500) << 6;
}

static s16 temp_to_offset_reg(long temp)
{
	return DIV_ROUND_CLOSEST(temp * 10, 625) << 3;
}

static int tmp464_enable_channels(struct tmp464_data *data)
{
	struct regmap *regmap = data->regmap;
	u16 enable = 0;
	int i;

	for (i = 0; i < data->channels; i++)
		if (data->channel[i].enabled)
			enable |= TMP464_CONFIG_REG_REN(i);

	return regmap_update_bits(regmap, TMP464_CONFIG_REG, TMP464_CONFIG_REG_REN_MASK, enable);
}

static int tmp464_chip_read(struct device *dev, u32 attr, int channel, long *val)
{
	struct tmp464_data *data = dev_get_drvdata(dev);

	switch (attr) {
	case hwmon_chip_update_interval:
		*val = data->update_interval;
		return 0;
	default:
		return -EOPNOTSUPP;
	}
}

static int tmp464_temp_read(struct device *dev, u32 attr, int channel, long *val)
{
	struct tmp464_data *data = dev_get_drvdata(dev);
	struct regmap *regmap = data->regmap;
	unsigned int regs[2];
	unsigned int regval;
	u16 regvals[2];
	int err = 0;

	switch (attr) {
	case hwmon_temp_max_alarm:
		err = regmap_read(regmap, TMP464_THERM_STATUS_REG, &regval);
		if (err < 0)
			break;
		*val = !!(regval & BIT(channel + 7));
		break;
	case hwmon_temp_crit_alarm:
		err = regmap_read(regmap, TMP464_THERM2_STATUS_REG, &regval);
		if (err < 0)
			break;
		*val = !!(regval & BIT(channel + 7));
		break;
	case hwmon_temp_fault:
		/*
		 * The chip clears TMP464_REMOTE_OPEN_REG after it is read
		 * and only updates it after the next measurement cycle is
		 * complete. That means we have to cache the value internally
		 * for one measurement cycle and report the cached value.
		 */
		if (!data->valid || time_after(jiffies, data->last_updated +
					       msecs_to_jiffies(data->update_interval))) {
			err = regmap_read(regmap, TMP464_REMOTE_OPEN_REG, &regval);
			if (err < 0)

Annotation

Implementation Notes