Commit 62c11e46 authored by Timothy Pearson's avatar Timothy Pearson Committed by Guenter Roeck
Browse files

hwmon: (adt7475) Add support for Imon readout on ADT7490



Add support for the ADT7490's Imon voltage readout. It is handled
largely the same way as the existing Vtt readout.

Signed-off-by: default avatarTimothy Pearson <tpearson@raptorengineering.com>
Co-developed-by: default avatarShawn Anastasio <sanastasio@raptorengineering.com>
Signed-off-by: default avatarShawn Anastasio <sanastasio@raptorengineering.com>
Link: https://lore.kernel.org/r/20230914223947.829025-1-tpearson@raptorengineering.com


Signed-off-by: default avatarGuenter Roeck <linux@roeck-us.net>
parent 2232f10d
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -90,7 +90,7 @@ ADT7476:

ADT7490:
  * 6 voltage inputs
  * 1 Imon input (not implemented)
  * 1 Imon input
  * PECI support (not implemented)
  * 2 GPIO pins (not implemented)
  * system acoustics optimizations (not implemented)
@@ -107,6 +107,7 @@ in2 VCC (4) VCC (4) VCC (4) VCC (3)
in3  5VIN   (20) 5VIN   (20)
in4  12VIN  (21) 12VIN  (21)
in5  VTT    (8)
in6  Imon   (19)
==== =========== =========== ========= ==========

Special Features
+62 −6
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
/* 7475 Common Registers */

#define REG_DEVREV2		0x12	/* ADT7490 only */
#define REG_IMON		0x1D	/* ADT7490 only */

#define REG_VTT			0x1E	/* ADT7490 only */
#define REG_EXTEND3		0x1F	/* ADT7490 only */
@@ -103,6 +104,9 @@
#define REG_VTT_MIN		0x84	/* ADT7490 only */
#define REG_VTT_MAX		0x86	/* ADT7490 only */

#define REG_IMON_MIN		0x85	/* ADT7490 only */
#define REG_IMON_MAX		0x87	/* ADT7490 only */

#define VID_VIDSEL		0x80	/* ADT7476 only */

#define CONFIG2_ATTN		0x20
@@ -123,7 +127,7 @@

/* ADT7475 Settings */

#define ADT7475_VOLTAGE_COUNT	5	/* Not counting Vtt */
#define ADT7475_VOLTAGE_COUNT	5	/* Not counting Vtt or Imon */
#define ADT7475_TEMP_COUNT	3
#define ADT7475_TACH_COUNT	4
#define ADT7475_PWM_COUNT	3
@@ -204,7 +208,7 @@ struct adt7475_data {
	u8 has_fan4:1;
	u8 has_vid:1;
	u32 alarms;
	u16 voltage[3][6];
	u16 voltage[3][7];
	u16 temp[7][3];
	u16 tach[2][4];
	u8 pwm[4][3];
@@ -215,7 +219,7 @@ struct adt7475_data {

	u8 vid;
	u8 vrm;
	const struct attribute_group *groups[9];
	const struct attribute_group *groups[10];
};

static struct i2c_driver adt7475_driver;
@@ -273,13 +277,14 @@ static inline u16 rpm2tach(unsigned long rpm)
}

/* Scaling factors for voltage inputs, taken from the ADT7490 datasheet */
static const int adt7473_in_scaling[ADT7475_VOLTAGE_COUNT + 1][2] = {
static const int adt7473_in_scaling[ADT7475_VOLTAGE_COUNT + 2][2] = {
	{ 45, 94 },	/* +2.5V */
	{ 175, 525 },	/* Vccp */
	{ 68, 71 },	/* Vcc */
	{ 93, 47 },	/* +5V */
	{ 120, 20 },	/* +12V */
	{ 45, 45 },	/* Vtt */
	{ 45, 45 },	/* Imon */
};

static inline int reg2volt(int channel, u16 reg, u8 bypass_attn)
@@ -369,11 +374,16 @@ static ssize_t voltage_store(struct device *dev,
			reg = VOLTAGE_MIN_REG(sattr->index);
		else
			reg = VOLTAGE_MAX_REG(sattr->index);
	} else {
	} else if (sattr->index == 5) {
		if (sattr->nr == MIN)
			reg = REG_VTT_MIN;
		else
			reg = REG_VTT_MAX;
	} else {
		if (sattr->nr == MIN)
			reg = REG_IMON_MIN;
		else
			reg = REG_IMON_MAX;
	}

	i2c_smbus_write_byte_data(client, reg,
@@ -1104,6 +1114,10 @@ static SENSOR_DEVICE_ATTR_2_RO(in5_input, voltage, INPUT, 5);
static SENSOR_DEVICE_ATTR_2_RW(in5_max, voltage, MAX, 5);
static SENSOR_DEVICE_ATTR_2_RW(in5_min, voltage, MIN, 5);
static SENSOR_DEVICE_ATTR_2_RO(in5_alarm, voltage, ALARM, 31);
static SENSOR_DEVICE_ATTR_2_RO(in6_input, voltage, INPUT, 6);
static SENSOR_DEVICE_ATTR_2_RW(in6_max, voltage, MAX, 6);
static SENSOR_DEVICE_ATTR_2_RW(in6_min, voltage, MIN, 6);
static SENSOR_DEVICE_ATTR_2_RO(in6_alarm, voltage, ALARM, 30);
static SENSOR_DEVICE_ATTR_2_RO(temp1_input, temp, INPUT, 0);
static SENSOR_DEVICE_ATTR_2_RO(temp1_alarm, temp, ALARM, 0);
static SENSOR_DEVICE_ATTR_2_RO(temp1_fault, temp, FAULT, 0);
@@ -1294,6 +1308,14 @@ static struct attribute *in5_attrs[] = {
	NULL
};

static struct attribute *in6_attrs[] = {
	&sensor_dev_attr_in6_input.dev_attr.attr,
	&sensor_dev_attr_in6_max.dev_attr.attr,
	&sensor_dev_attr_in6_min.dev_attr.attr,
	&sensor_dev_attr_in6_alarm.dev_attr.attr,
	NULL
};

static struct attribute *vid_attrs[] = {
	&dev_attr_cpu0_vid.attr,
	&dev_attr_vrm.attr,
@@ -1307,6 +1329,7 @@ static const struct attribute_group in0_attr_group = { .attrs = in0_attrs };
static const struct attribute_group in3_attr_group = { .attrs = in3_attrs };
static const struct attribute_group in4_attr_group = { .attrs = in4_attrs };
static const struct attribute_group in5_attr_group = { .attrs = in5_attrs };
static const struct attribute_group in6_attr_group = { .attrs = in6_attrs };
static const struct attribute_group vid_attr_group = { .attrs = vid_attrs };

static int adt7475_detect(struct i2c_client *client,
@@ -1389,6 +1412,18 @@ static int adt7475_update_limits(struct i2c_client *client)
		data->voltage[MAX][5] = ret << 2;
	}

	if (data->has_voltage & (1 << 6)) {
		ret = adt7475_read(REG_IMON_MIN);
		if (ret < 0)
			return ret;
		data->voltage[MIN][6] = ret << 2;

		ret = adt7475_read(REG_IMON_MAX);
		if (ret < 0)
			return ret;
		data->voltage[MAX][6] = ret << 2;
	}

	for (i = 0; i < ADT7475_TEMP_COUNT; i++) {
		/* Adjust values so they match the input precision */
		ret = adt7475_read(TEMP_MIN_REG(i));
@@ -1663,7 +1698,7 @@ static int adt7475_probe(struct i2c_client *client)
		revision = adt7475_read(REG_DEVID2) & 0x07;
		break;
	case adt7490:
		data->has_voltage = 0x3e;	/* in1 to in5 */
		data->has_voltage = 0x7e;	/* in1 to in6 */
		revision = adt7475_read(REG_DEVID2) & 0x03;
		if (revision == 0x03)
			revision += adt7475_read(REG_DEVREV2);
@@ -1775,6 +1810,9 @@ static int adt7475_probe(struct i2c_client *client)
	if (data->has_voltage & (1 << 5)) {
		data->groups[group_num++] = &in5_attr_group;
	}
	if (data->has_voltage & (1 << 6)) {
		data->groups[group_num++] = &in6_attr_group;
	}
	if (data->has_vid) {
		data->vrm = vid_which_vrm();
		data->groups[group_num] = &vid_attr_group;
@@ -1960,6 +1998,24 @@ static int adt7475_update_measure(struct device *dev)
			((ext >> 4) & 3);
	}

	if (data->has_voltage & (1 << 6)) {
		ret = adt7475_read(REG_STATUS4);
		if (ret < 0)
			return ret;
		data->alarms |= ret << 24;

		ret = adt7475_read(REG_EXTEND3);
		if (ret < 0)
			return ret;
		ext = ret;

		ret = adt7475_read(REG_IMON);
		if (ret < 0)
			return ret;
		data->voltage[INPUT][6] = ret << 2 |
			((ext >> 6) & 3);
	}

	for (i = 0; i < ADT7475_TACH_COUNT; i++) {
		if (i == 3 && !data->has_fan4)
			continue;