Skip to content

Commit

Permalink
hwmon: (adt7475) Add support for Imon readout on ADT7490
Browse files Browse the repository at this point in the history
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 <[email protected]>
Co-developed-by: Shawn Anastasio <[email protected]>
Signed-off-by: Shawn Anastasio <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Guenter Roeck <[email protected]>
  • Loading branch information
madscientist159 authored and groeck committed Oct 27, 2023
1 parent 2232f10 commit 62c11e4
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 7 deletions.
3 changes: 2 additions & 1 deletion Documentation/hwmon/adt7475.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
68 changes: 62 additions & 6 deletions drivers/hwmon/adt7475.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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];
Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 62c11e4

Please sign in to comment.