drivers/hwmon/ultra45_env.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hwmon/ultra45_env.c
Extension
.c
Size
8582 bytes
Lines
324
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 env {
	void __iomem	*regs;
	spinlock_t	lock;

	struct device	*hwmon_dev;
};

static u8 env_read(struct env *p, u8 ireg)
{
	u8 ret;

	spin_lock(&p->lock);
	writeb(ireg, p->regs + REG_ADDR);
	ret = readb(p->regs + REG_DATA);
	spin_unlock(&p->lock);

	return ret;
}

static void env_write(struct env *p, u8 ireg, u8 val)
{
	spin_lock(&p->lock);
	writeb(ireg, p->regs + REG_ADDR);
	writeb(val, p->regs + REG_DATA);
	spin_unlock(&p->lock);
}

/*
 * There seems to be a adr7462 providing these values, thus a lot
 * of these calculations are borrowed from the adt7470 driver.
 */
#define FAN_PERIOD_TO_RPM(x)	((90000 * 60) / (x))
#define FAN_RPM_TO_PERIOD	FAN_PERIOD_TO_RPM
#define FAN_PERIOD_INVALID	(0xff << 8)
#define FAN_DATA_VALID(x)	((x) && (x) != FAN_PERIOD_INVALID)

static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr,
			      char *buf)
{
	int fan_nr = to_sensor_dev_attr(attr)->index;
	struct env *p = dev_get_drvdata(dev);
	int rpm, period;
	u8 val;

	val = env_read(p, IREG_FAN0 + fan_nr);
	period = (int) val << 8;
	if (FAN_DATA_VALID(period))
		rpm = FAN_PERIOD_TO_RPM(period);
	else
		rpm = 0;

	return sprintf(buf, "%d\n", rpm);
}

static ssize_t set_fan_speed(struct device *dev, struct device_attribute *attr,
			     const char *buf, size_t count)
{
	int fan_nr = to_sensor_dev_attr(attr)->index;
	unsigned long rpm;
	struct env *p = dev_get_drvdata(dev);
	int period;
	u8 val;
	int err;

	err = kstrtoul(buf, 10, &rpm);
	if (err)
		return err;

	if (!rpm)
		return -EINVAL;

	period = FAN_RPM_TO_PERIOD(rpm);
	val = period >> 8;
	env_write(p, IREG_FAN0 + fan_nr, val);

	return count;
}

static ssize_t show_fan_fault(struct device *dev, struct device_attribute *attr,
			      char *buf)
{
	int fan_nr = to_sensor_dev_attr(attr)->index;
	struct env *p = dev_get_drvdata(dev);
	u8 val = env_read(p, IREG_FAN_STAT);
	return sprintf(buf, "%d\n", (val & (1 << fan_nr)) ? 1 : 0);
}

#define fan(index)							\
static SENSOR_DEVICE_ATTR(fan##index##_speed, S_IRUGO | S_IWUSR,	\
		show_fan_speed, set_fan_speed, index);			\

Annotation

Implementation Notes