drivers/hwmon/adm9240.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hwmon/adm9240.c
Extension
.c
Size
19981 bytes
Lines
821
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 adm9240_data {
	struct device *dev;
	struct regmap *regmap;

	u8 fan_div[2];		/* rw	fan1_div, read-only accessor */
	u8 vrm;			/* --	vrm set on startup, no accessor */
};

/* write new fan div, callers must hold data->update_lock */
static int adm9240_write_fan_div(struct adm9240_data *data, int channel, u8 fan_div)
{
	unsigned int reg, old, shift = (channel + 2) * 2;
	int err;

	err = regmap_read(data->regmap, ADM9240_REG_VID_FAN_DIV, &reg);
	if (err < 0)
		return err;
	old = (reg >> shift) & 3;
	reg &= ~(3 << shift);
	reg |= (fan_div << shift);
	err = regmap_write(data->regmap, ADM9240_REG_VID_FAN_DIV, reg);
	if (err < 0)
		return err;
	dev_dbg(data->dev,
		"fan%d clock divider changed from %lu to %lu\n",
		channel + 1, BIT(old), BIT(fan_div));

	return 0;
}

/*
 * set fan speed low limit:
 *
 * - value is zero: disable fan speed low limit alarm
 *
 * - value is below fan speed measurement range: enable fan speed low
 *   limit alarm to be asserted while fan speed too slow to measure
 *
 * - otherwise: select fan clock divider to suit fan speed low limit,
 *   measurement code may adjust registers to ensure fan speed reading
 */
static int adm9240_fan_min_write(struct adm9240_data *data, int channel, long val)
{
	u8 new_div;
	u8 fan_min;
	int err;

	if (!val) {
		fan_min = 255;
		new_div = data->fan_div[channel];

		dev_dbg(data->dev, "fan%u low limit set disabled\n", channel + 1);
	} else if (val < 1350000 / (8 * 254)) {
		new_div = 3;
		fan_min = 254;

		dev_dbg(data->dev, "fan%u low limit set minimum %u\n",
			channel + 1, FAN_FROM_REG(254, BIT(new_div)));
	} else {
		unsigned int new_min = 1350000 / val;

		new_div = 0;
		while (new_min > 192 && new_div < 3) {
			new_div++;
			new_min /= 2;
		}
		if (!new_min) /* keep > 0 */
			new_min++;

		fan_min = new_min;

		dev_dbg(data->dev, "fan%u low limit set fan speed %u\n",
			channel + 1, FAN_FROM_REG(new_min, BIT(new_div)));
	}

	if (new_div != data->fan_div[channel]) {
		data->fan_div[channel] = new_div;
		adm9240_write_fan_div(data, channel, new_div);
	}
	err = regmap_write(data->regmap, ADM9240_REG_FAN_MIN(channel), fan_min);

	return err;
}

static ssize_t cpu0_vid_show(struct device *dev,
			     struct device_attribute *attr, char *buf)
{
	struct adm9240_data *data = dev_get_drvdata(dev);
	unsigned int regval;
	int err;

Annotation

Implementation Notes