drivers/hwmon/sbtsi_temp.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hwmon/sbtsi_temp.c
Extension
.c
Size
6739 bytes
Lines
251
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 sbtsi_data {
	struct i2c_client *client;
	bool ext_range_mode;
	bool read_order;
};

/*
 * From SB-TSI spec: CPU temperature readings and limit registers encode the
 * temperature in increments of 0.125 from 0 to 255.875. The "high byte"
 * register encodes the base-2 of the integer portion, and the upper 3 bits of
 * the "low byte" encode in base-2 the decimal portion.
 *
 * e.g. INT=0x19, DEC=0x20 represents 25.125 degrees Celsius
 *
 * Therefore temperature in millidegree Celsius =
 *   (INT + DEC / 256) * 1000 = (INT * 8 + DEC / 32) * 125
 */
static inline int sbtsi_reg_to_mc(s32 integer, s32 decimal)
{
	return ((integer << 3) + (decimal >> 5)) * 125;
}

/*
 * Inversely, given temperature in millidegree Celsius
 *   INT = (TEMP / 125) / 8
 *   DEC = ((TEMP / 125) % 8) * 32
 * Caller have to make sure temp doesn't exceed 255875, the max valid value.
 */
static inline void sbtsi_mc_to_reg(s32 temp, u8 *integer, u8 *decimal)
{
	temp /= 125;
	*integer = temp >> 3;
	*decimal = (temp & 0x7) << 5;
}

static int sbtsi_read(struct device *dev, enum hwmon_sensor_types type,
		      u32 attr, int channel, long *val)
{
	struct sbtsi_data *data = dev_get_drvdata(dev);
	s32 temp_int, temp_dec;

	switch (attr) {
	case hwmon_temp_input:
		if (data->read_order) {
			temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_DEC);
			temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_INT);
		} else {
			temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_INT);
			temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_DEC);
		}
		break;
	case hwmon_temp_max:
		temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_HIGH_INT);
		temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_HIGH_DEC);
		break;
	case hwmon_temp_min:
		temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_LOW_INT);
		temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_LOW_DEC);
		break;
	default:
		return -EINVAL;
	}


	if (temp_int < 0)
		return temp_int;
	if (temp_dec < 0)
		return temp_dec;

	*val = sbtsi_reg_to_mc(temp_int, temp_dec);
	if (data->ext_range_mode)
		*val -= SBTSI_TEMP_EXT_RANGE_ADJ;

	return 0;
}

static int sbtsi_write(struct device *dev, enum hwmon_sensor_types type,
		       u32 attr, int channel, long val)
{
	struct sbtsi_data *data = dev_get_drvdata(dev);
	int reg_int, reg_dec, err;
	u8 temp_int, temp_dec;

	switch (attr) {
	case hwmon_temp_max:
		reg_int = SBTSI_REG_TEMP_HIGH_INT;
		reg_dec = SBTSI_REG_TEMP_HIGH_DEC;
		break;
	case hwmon_temp_min:
		reg_int = SBTSI_REG_TEMP_LOW_INT;

Annotation

Implementation Notes