drivers/hwmon/lm63.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hwmon/lm63.c
Extension
.c
Size
40651 bytes
Lines
1329
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 lm63_data {
	struct i2c_client *client;
	struct mutex update_lock;
	const struct attribute_group *groups[5];
	bool valid; /* false until following fields are valid */
	char lut_valid; /* zero until lut fields are valid */
	unsigned long last_updated; /* in jiffies */
	unsigned long lut_last_updated; /* in jiffies */
	enum chips kind;
	int temp2_offset;

	int update_interval;	/* in milliseconds */
	int max_convrate_hz;
	int lut_size;		/* 8 or 12 */

	/* registers values */
	u8 config, config_fan;
	u16 fan[2];	/* 0: input
			   1: low limit */
	u8 pwm1_freq;
	u8 pwm1[13];	/* 0: current output
			   1-12: lookup table */
	s8 temp8[15];	/* 0: local input
			   1: local high limit
			   2: remote critical limit
			   3-14: lookup table */
	s16 temp11[4];	/* 0: remote input
			   1: remote low limit
			   2: remote high limit
			   3: remote offset */
	u16 temp11u;	/* remote input (unsigned) */
	u8 temp2_crit_hyst;
	u8 lut_temp_hyst;
	u8 alarms;
	bool pwm_highres;
	bool lut_temp_highres;
	bool remote_unsigned; /* true if unsigned remote upper limits */
	bool trutherm;
};

static inline int temp8_from_reg(struct lm63_data *data, int nr)
{
	if (data->remote_unsigned)
		return TEMP8_FROM_REG((u8)data->temp8[nr]);
	return TEMP8_FROM_REG(data->temp8[nr]);
}

static inline int lut_temp_from_reg(struct lm63_data *data, int nr)
{
	return data->temp8[nr] * (data->lut_temp_highres ? 500 : 1000);
}

static inline int lut_temp_to_reg(struct lm63_data *data, long val)
{
	val -= data->temp2_offset;
	if (data->lut_temp_highres)
		return DIV_ROUND_CLOSEST(clamp_val(val, 0, 127500), 500);
	else
		return DIV_ROUND_CLOSEST(clamp_val(val, 0, 127000), 1000);
}

/*
 * Update the lookup table register cache.
 * client->update_lock must be held when calling this function.
 */
static void lm63_update_lut(struct lm63_data *data)
{
	struct i2c_client *client = data->client;
	int i;

	if (time_after(jiffies, data->lut_last_updated + 5 * HZ) ||
	    !data->lut_valid) {
		for (i = 0; i < data->lut_size; i++) {
			data->pwm1[1 + i] = i2c_smbus_read_byte_data(client,
					    LM63_REG_LUT_PWM(i));
			data->temp8[3 + i] = i2c_smbus_read_byte_data(client,
					     LM63_REG_LUT_TEMP(i));
		}
		data->lut_temp_hyst = i2c_smbus_read_byte_data(client,
				      LM63_REG_LUT_TEMP_HYST);

		data->lut_last_updated = jiffies;
		data->lut_valid = 1;
	}
}

static struct lm63_data *lm63_update_device(struct device *dev)
{
	struct lm63_data *data = dev_get_drvdata(dev);
	struct i2c_client *client = data->client;

Annotation

Implementation Notes