drivers/hwmon/lan966x-hwmon.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hwmon/lan966x-hwmon.c
Extension
.c
Size
9811 bytes
Lines
397
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 lan966x_hwmon {
	struct regmap *regmap_pvt;
	struct regmap *regmap_fan;
	struct clk *clk;
	unsigned long clk_rate;
};

static int lan966x_hwmon_read_temp(struct device *dev, long *val)
{
	struct lan966x_hwmon *hwmon = dev_get_drvdata(dev);
	unsigned int data;
	int ret;

	ret = regmap_read(hwmon->regmap_pvt, PVT_SENSOR_STAT, &data);
	if (ret < 0)
		return ret;

	if (!(data & SENSOR_STAT_DATA_VALID))
		return -ENODATA;

	*val = polynomial_calc(&poly_N_to_temp,
			       FIELD_GET(SENSOR_STAT_DATA, data));

	return 0;
}

static int lan966x_hwmon_read_fan(struct device *dev, long *val)
{
	struct lan966x_hwmon *hwmon = dev_get_drvdata(dev);
	unsigned int data;
	int ret;

	ret = regmap_read(hwmon->regmap_fan, FAN_CNT, &data);
	if (ret < 0)
		return ret;

	/*
	 * Data is given in pulses per second. Assume two pulses
	 * per revolution.
	 */
	*val = FIELD_GET(FAN_CNT_DATA, data) * 60 / 2;

	return 0;
}

static int lan966x_hwmon_read_pwm(struct device *dev, long *val)
{
	struct lan966x_hwmon *hwmon = dev_get_drvdata(dev);
	unsigned int data;
	int ret;

	ret = regmap_read(hwmon->regmap_fan, FAN_CFG, &data);
	if (ret < 0)
		return ret;

	*val = FIELD_GET(FAN_CFG_DUTY_CYCLE, data);

	return 0;
}

static int lan966x_hwmon_read_pwm_freq(struct device *dev, long *val)
{
	struct lan966x_hwmon *hwmon = dev_get_drvdata(dev);
	unsigned long tmp;
	unsigned int data;
	int ret;

	ret = regmap_read(hwmon->regmap_fan, FAN_PWM_FREQ, &data);
	if (ret < 0)
		return ret;

	/*
	 * Datasheet says it is sys_clk / 256 / pwm_freq. But in reality
	 * it is sys_clk / 256 / (pwm_freq + 1).
	 */
	data = FIELD_GET(FAN_PWM_FREQ_FREQ, data) + 1;
	tmp = DIV_ROUND_CLOSEST(hwmon->clk_rate, 256);
	*val = DIV_ROUND_CLOSEST(tmp, data);

	return 0;
}

static int lan966x_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
			      u32 attr, int channel, long *val)
{
	switch (type) {
	case hwmon_temp:
		return lan966x_hwmon_read_temp(dev, val);
	case hwmon_fan:
		return lan966x_hwmon_read_fan(dev, val);

Annotation

Implementation Notes