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: ADT7490:
* 6 voltage inputs * 6 voltage inputs
* 1 Imon input (not implemented) * 1 Imon input
* PECI support (not implemented) * PECI support (not implemented)
* 2 GPIO pins (not implemented) * 2 GPIO pins (not implemented)
* system acoustics optimizations (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) in3 5VIN (20) 5VIN (20)
in4 12VIN (21) 12VIN (21) in4 12VIN (21) 12VIN (21)
in5 VTT (8) in5 VTT (8)
in6 Imon (19)
==== =========== =========== ========= ========== ==== =========== =========== ========= ==========
Special Features Special Features

View File

@ -43,6 +43,7 @@
/* 7475 Common Registers */ /* 7475 Common Registers */
#define REG_DEVREV2 0x12 /* ADT7490 only */ #define REG_DEVREV2 0x12 /* ADT7490 only */
#define REG_IMON 0x1D /* ADT7490 only */
#define REG_VTT 0x1E /* ADT7490 only */ #define REG_VTT 0x1E /* ADT7490 only */
#define REG_EXTEND3 0x1F /* ADT7490 only */ #define REG_EXTEND3 0x1F /* ADT7490 only */
@ -103,6 +104,9 @@
#define REG_VTT_MIN 0x84 /* ADT7490 only */ #define REG_VTT_MIN 0x84 /* ADT7490 only */
#define REG_VTT_MAX 0x86 /* 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 VID_VIDSEL 0x80 /* ADT7476 only */
#define CONFIG2_ATTN 0x20 #define CONFIG2_ATTN 0x20
@ -123,7 +127,7 @@
/* ADT7475 Settings */ /* 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_TEMP_COUNT 3
#define ADT7475_TACH_COUNT 4 #define ADT7475_TACH_COUNT 4
#define ADT7475_PWM_COUNT 3 #define ADT7475_PWM_COUNT 3
@ -204,7 +208,7 @@ struct adt7475_data {
u8 has_fan4:1; u8 has_fan4:1;
u8 has_vid:1; u8 has_vid:1;
u32 alarms; u32 alarms;
u16 voltage[3][6]; u16 voltage[3][7];
u16 temp[7][3]; u16 temp[7][3];
u16 tach[2][4]; u16 tach[2][4];
u8 pwm[4][3]; u8 pwm[4][3];
@ -215,7 +219,7 @@ struct adt7475_data {
u8 vid; u8 vid;
u8 vrm; u8 vrm;
const struct attribute_group *groups[9]; const struct attribute_group *groups[10];
}; };
static struct i2c_driver adt7475_driver; 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 */ /* 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 */ { 45, 94 }, /* +2.5V */
{ 175, 525 }, /* Vccp */ { 175, 525 }, /* Vccp */
{ 68, 71 }, /* Vcc */ { 68, 71 }, /* Vcc */
{ 93, 47 }, /* +5V */ { 93, 47 }, /* +5V */
{ 120, 20 }, /* +12V */ { 120, 20 }, /* +12V */
{ 45, 45 }, /* Vtt */ { 45, 45 }, /* Vtt */
{ 45, 45 }, /* Imon */
}; };
static inline int reg2volt(int channel, u16 reg, u8 bypass_attn) 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); reg = VOLTAGE_MIN_REG(sattr->index);
else else
reg = VOLTAGE_MAX_REG(sattr->index); reg = VOLTAGE_MAX_REG(sattr->index);
} else { } else if (sattr->index == 5) {
if (sattr->nr == MIN) if (sattr->nr == MIN)
reg = REG_VTT_MIN; reg = REG_VTT_MIN;
else else
reg = REG_VTT_MAX; 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, 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_max, voltage, MAX, 5);
static SENSOR_DEVICE_ATTR_2_RW(in5_min, voltage, MIN, 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(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_input, temp, INPUT, 0);
static SENSOR_DEVICE_ATTR_2_RO(temp1_alarm, temp, ALARM, 0); static SENSOR_DEVICE_ATTR_2_RO(temp1_alarm, temp, ALARM, 0);
static SENSOR_DEVICE_ATTR_2_RO(temp1_fault, temp, FAULT, 0); static SENSOR_DEVICE_ATTR_2_RO(temp1_fault, temp, FAULT, 0);
@ -1294,6 +1308,14 @@ static struct attribute *in5_attrs[] = {
NULL 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[] = { static struct attribute *vid_attrs[] = {
&dev_attr_cpu0_vid.attr, &dev_attr_cpu0_vid.attr,
&dev_attr_vrm.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 in3_attr_group = { .attrs = in3_attrs };
static const struct attribute_group in4_attr_group = { .attrs = in4_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 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 const struct attribute_group vid_attr_group = { .attrs = vid_attrs };
static int adt7475_detect(struct i2c_client *client, 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; 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++) { for (i = 0; i < ADT7475_TEMP_COUNT; i++) {
/* Adjust values so they match the input precision */ /* Adjust values so they match the input precision */
ret = adt7475_read(TEMP_MIN_REG(i)); 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; revision = adt7475_read(REG_DEVID2) & 0x07;
break; break;
case adt7490: case adt7490:
data->has_voltage = 0x3e; /* in1 to in5 */ data->has_voltage = 0x7e; /* in1 to in6 */
revision = adt7475_read(REG_DEVID2) & 0x03; revision = adt7475_read(REG_DEVID2) & 0x03;
if (revision == 0x03) if (revision == 0x03)
revision += adt7475_read(REG_DEVREV2); revision += adt7475_read(REG_DEVREV2);
@ -1775,6 +1810,9 @@ static int adt7475_probe(struct i2c_client *client)
if (data->has_voltage & (1 << 5)) { if (data->has_voltage & (1 << 5)) {
data->groups[group_num++] = &in5_attr_group; data->groups[group_num++] = &in5_attr_group;
} }
if (data->has_voltage & (1 << 6)) {
data->groups[group_num++] = &in6_attr_group;
}
if (data->has_vid) { if (data->has_vid) {
data->vrm = vid_which_vrm(); data->vrm = vid_which_vrm();
data->groups[group_num] = &vid_attr_group; data->groups[group_num] = &vid_attr_group;
@ -1960,6 +1998,24 @@ static int adt7475_update_measure(struct device *dev)
((ext >> 4) & 3); ((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++) { for (i = 0; i < ADT7475_TACH_COUNT; i++) {
if (i == 3 && !data->has_fan4) if (i == 3 && !data->has_fan4)
continue; continue;