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: Timothy Pearson <tpearson@raptorengineering.com>
Co-developed-by: Shawn Anastasio <sanastasio@raptorengineering.com>
Signed-off-by: Shawn Anastasio <sanastasio@raptorengineering.com>
Link: https://lore.kernel.org/r/20230914223947.829025-1-tpearson@raptorengineering.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
Timothy Pearson 2023-09-14 17:39:47 -05:00 committed by Guenter Roeck
parent 2232f10d71
commit 62c11e461c
2 changed files with 64 additions and 7 deletions

View File

@ -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

View File

@ -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;