drivers/hwmon/tmp513.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hwmon/tmp513.c
Extension
.c
Size
20210 bytes
Lines
764
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 tmp51x_data {
	u16 shunt_config;
	u16 pga_gain;
	u32 vbus_range_uvolt;

	u16 temp_config;
	u32 nfactor[3];

	u32 shunt_uohms;

	u32 curr_lsb_ua;
	u32 pwr_lsb_uw;

	u8 max_channels;
	struct regmap *regmap;
};

// Set the shift based on the gain: 8 -> 1, 4 -> 2, 2 -> 3, 1 -> 4
static inline u8 tmp51x_get_pga_shift(struct tmp51x_data *data)
{
	return 5 - ffs(data->pga_gain);
}

static int tmp51x_get_value(struct tmp51x_data *data, u8 reg, u8 pos,
			    unsigned int regval, long *val)
{
	switch (reg) {
	case TMP51X_STATUS:
		*val = (regval >> pos) & 1;
		break;
	case TMP51X_SHUNT_CURRENT_RESULT:
	case TMP51X_SHUNT_CURRENT_H_LIMIT:
	case TMP51X_SHUNT_CURRENT_L_LIMIT:
		/*
		 * The valus is read in voltage in the chip but reported as
		 * current to the user.
		 * 2's complement number shifted by one to four depending
		 * on the pga gain setting. 1lsb = 10uV
		 */
		*val = sign_extend32(regval,
				     reg == TMP51X_SHUNT_CURRENT_RESULT ?
				     16 - tmp51x_get_pga_shift(data) : 15);
		*val = DIV_ROUND_CLOSEST(*val * 10 * (long)MILLI, (long)data->shunt_uohms);

		break;
	case TMP51X_BUS_VOLTAGE_RESULT:
	case TMP51X_BUS_VOLTAGE_H_LIMIT:
	case TMP51X_BUS_VOLTAGE_L_LIMIT:
		// 1lsb = 4mV
		*val = (regval >> TMP51X_BUS_VOLTAGE_SHIFT) * 4;
		break;
	case TMP51X_POWER_RESULT:
	case TMP51X_POWER_LIMIT:
		// Power = (current * BusVoltage) / 5000
		*val = regval * data->pwr_lsb_uw;
		break;
	case TMP51X_BUS_CURRENT_RESULT:
		// Current = (ShuntVoltage * CalibrationRegister) / 4096
		*val = sign_extend32(regval, 15) * (long)data->curr_lsb_ua;
		*val = DIV_ROUND_CLOSEST(*val, (long)MILLI);
		break;
	case TMP51X_LOCAL_TEMP_RESULT:
	case TMP51X_REMOTE_TEMP_RESULT_1:
	case TMP51X_REMOTE_TEMP_RESULT_2:
	case TMP513_REMOTE_TEMP_RESULT_3:
	case TMP51X_LOCAL_TEMP_LIMIT:
	case TMP51X_REMOTE_TEMP_LIMIT_1:
	case TMP51X_REMOTE_TEMP_LIMIT_2:
	case TMP513_REMOTE_TEMP_LIMIT_3:
		// 1lsb = 0.0625 degrees centigrade
		*val = sign_extend32(regval, 15) >> TMP51X_TEMP_SHIFT;
		*val = DIV_ROUND_CLOSEST(*val * 625, 10);
		break;
	case TMP51X_N_FACTOR_AND_HYST_1:
		// 1lsb = 0.5 degrees centigrade
		*val = (regval & TMP51X_HYST_MASK) * 500;
		break;
	default:
		// Programmer goofed
		WARN_ON_ONCE(1);
		*val = 0;
		return -EOPNOTSUPP;
	}

	return 0;
}

static int tmp51x_set_value(struct tmp51x_data *data, u8 reg, long val)
{
	int regval, max_val;

Annotation

Implementation Notes