diff mbox series

hwmon: (emc1403) Add support for EMC1438.

Message ID 20240426140937.609172-1-lars.petter.mostad@appear.net (mailing list archive)
State Changes Requested
Headers show
Series hwmon: (emc1403) Add support for EMC1438. | expand

Commit Message

Lars Petter Mostad April 26, 2024, 2:09 p.m. UTC
EMC1438 is similar to EMC14x4, but supports four
more external temperature sensors.

Signed-off-by: Lars Petter Mostad <lars.petter.mostad@appear.net>
---
 drivers/hwmon/emc1403.c | 119 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 117 insertions(+), 2 deletions(-)


base-commit: e723f6ca39fb54ae31f79b5af74fe8496308d4de

Comments

Guenter Roeck April 28, 2024, 6:15 p.m. UTC | #1
On Fri, Apr 26, 2024 at 04:09:37PM +0200, Lars Petter Mostad wrote:
> EMC1438 is similar to EMC14x4, but supports four
> more external temperature sensors.
> 
> Signed-off-by: Lars Petter Mostad <lars.petter.mostad@appear.net>

Conversion to the _with_info API is long overdue for this driver
(not mandatory here but it would reduce driver size a lot).

> ---
>  drivers/hwmon/emc1403.c | 119 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 117 insertions(+), 2 deletions(-)
> 
> 
> base-commit: e723f6ca39fb54ae31f79b5af74fe8496308d4de
> 
> diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c
> index d370efd6f986..1ce01baf7a1e 100644
> --- a/drivers/hwmon/emc1403.c
> +++ b/drivers/hwmon/emc1403.c
> @@ -24,12 +24,12 @@
>  #define THERMAL_SMSC_ID_REG	0xfe
>  #define THERMAL_REVISION_REG	0xff
>  
> -enum emc1403_chip { emc1402, emc1403, emc1404 };
> +enum emc1403_chip { emc1402, emc1403, emc1404, emc1408 };

There is no EMC1408, and if there was it might not be compatible with
EMC1438.

The 8-channel chips (emc1428 and emc1438) suppport signed data
and limit registers. This will need to be handled.

I don't know if this also applies to any of the emc144X chips - the
datasheets for those chips are not available to the public. AFAICS all
other chips in the series (i.e., all chips with less than 8 channels)
have unsigned temperature registers.

Guenter
Lars Petter Mostad April 30, 2024, 11:10 a.m. UTC | #2
On Sun, Apr 28, 2024 at 8:15 PM Guenter Roeck <linux@roeck-us.net> wrote:
> > -enum emc1403_chip { emc1402, emc1403, emc1404 };
> > +enum emc1403_chip { emc1402, emc1403, emc1404, emc1408 };
>
> There is no EMC1408, and if there was it might not be compatible with
> EMC1438.

Yes, using the name of a chip that does not (yet) exist is not good. I was going
on the apparent pattern that the name emc140n was used for things common
for all emc14xn chips.

> The 8-channel chips (emc1428 and emc1438) suppport signed data
> and limit registers. This will need to be handled.

I see that my glance at the EMC14xx datasheets was way too brief. EMC1438 looked
like a straight extension of the currently supported chips to 8 channels.
I totally missed the sign bit.

I guess sign_extend32 can be used to handle two's complement for signed chips.
This I guess would mean putting some extra info into thermal_data to let the
show/store functions know whether they are handling a signed chip or not. This
might make the driver unnecessarily messy, as apparently nobody else has been
interested in support for the chips with signed data. If so I withdraw this
patch.

Should this driver be kept unsigned only?

Regards,
Lars Petter
Guenter Roeck April 30, 2024, 3:51 p.m. UTC | #3
On 4/30/24 04:10, Lars Petter Mostad wrote:
> On Sun, Apr 28, 2024 at 8:15 PM Guenter Roeck <linux@roeck-us.net> wrote:
>>> -enum emc1403_chip { emc1402, emc1403, emc1404 };
>>> +enum emc1403_chip { emc1402, emc1403, emc1404, emc1408 };
>>
>> There is no EMC1408, and if there was it might not be compatible with
>> EMC1438.
> 
> Yes, using the name of a chip that does not (yet) exist is not good. I was going
> on the apparent pattern that the name emc140n was used for things common
> for all emc14xn chips.
> 

I figured that much, but that should not include virtual chips.
You might consider adding support for emc1428 as well, though; unless
I am missing something the only difference should be the chip ID.

>> The 8-channel chips (emc1428 and emc1438) suppport signed data
>> and limit registers. This will need to be handled.
> 
> I see that my glance at the EMC14xx datasheets was way too brief. EMC1438 looked
> like a straight extension of the currently supported chips to 8 channels.
> I totally missed the sign bit.
> 
No problem; I only accidentally noticed it myself.

> I guess sign_extend32 can be used to handle two's complement for signed chips.

Yes.

> This I guess would mean putting some extra info into thermal_data to let the
> show/store functions know whether they are handling a signed chip or not. This
> might make the driver unnecessarily messy, as apparently nobody else has been
> interested in support for the chips with signed data. If so I withdraw this
> patch.
> 
> Should this driver be kept unsigned only?
> 

I'd prefer to have support for the 8-channel chips (and with it for signed
temperature data) added. As mentioned in my other reply, I would suggest though
that you convert the driver to use the with_info API. That would move a lot
of code into the hwmon core and make it much easier to add support for additional
chips, for signed/unsigned handling, and for handling 16 bit wide registers.

In this context, could you send me a register dump of emc1438 (and of any
other chips of the chips supported by the emc1403 driver if you have access
to them) ? I'd like to add module tests for those chips.

Thanks,
Guenter
diff mbox series

Patch

diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c
index d370efd6f986..1ce01baf7a1e 100644
--- a/drivers/hwmon/emc1403.c
+++ b/drivers/hwmon/emc1403.c
@@ -24,12 +24,12 @@ 
 #define THERMAL_SMSC_ID_REG	0xfe
 #define THERMAL_REVISION_REG	0xff
 
-enum emc1403_chip { emc1402, emc1403, emc1404 };
+enum emc1403_chip { emc1402, emc1403, emc1404, emc1408 };
 
 struct thermal_data {
 	struct regmap *regmap;
 	struct mutex mutex;
-	const struct attribute_group *groups[4];
+	const struct attribute_group *groups[5];
 };
 
 static ssize_t temp_show(struct device *dev, struct device_attribute *attr,
@@ -209,6 +209,54 @@  static SENSOR_DEVICE_ATTR_RO(temp4_min_hyst, min_hyst, 0x2D);
 static SENSOR_DEVICE_ATTR_RO(temp4_max_hyst, hyst, 0x2C);
 static SENSOR_DEVICE_ATTR_RO(temp4_crit_hyst, hyst, 0x30);
 
+static SENSOR_DEVICE_ATTR_RW(temp5_min, temp, 0x51);
+static SENSOR_DEVICE_ATTR_RW(temp5_max, temp, 0x50);
+static SENSOR_DEVICE_ATTR_RW(temp5_crit, temp, 0x64);
+static SENSOR_DEVICE_ATTR_RO(temp5_input, temp, 0x41);
+static SENSOR_DEVICE_ATTR_2_RO(temp5_fault, bit, 0x1b, 0x10);
+static SENSOR_DEVICE_ATTR_2_RO(temp5_min_alarm, bit, 0x36, 0x10);
+static SENSOR_DEVICE_ATTR_2_RO(temp5_max_alarm, bit, 0x35, 0x10);
+static SENSOR_DEVICE_ATTR_2_RO(temp5_crit_alarm, bit, 0x37, 0x10);
+static SENSOR_DEVICE_ATTR_RO(temp5_min_hyst, min_hyst, 0x51);
+static SENSOR_DEVICE_ATTR_RO(temp5_max_hyst, hyst, 0x50);
+static SENSOR_DEVICE_ATTR_RO(temp5_crit_hyst, hyst, 0x64);
+
+static SENSOR_DEVICE_ATTR_RW(temp6_min, temp, 0x55);
+static SENSOR_DEVICE_ATTR_RW(temp6_max, temp, 0x54);
+static SENSOR_DEVICE_ATTR_RW(temp6_crit, temp, 0x65);
+static SENSOR_DEVICE_ATTR_RO(temp6_input, temp, 0x43);
+static SENSOR_DEVICE_ATTR_2_RO(temp6_fault, bit, 0x1b, 0x20);
+static SENSOR_DEVICE_ATTR_2_RO(temp6_min_alarm, bit, 0x36, 0x20);
+static SENSOR_DEVICE_ATTR_2_RO(temp6_max_alarm, bit, 0x35, 0x20);
+static SENSOR_DEVICE_ATTR_2_RO(temp6_crit_alarm, bit, 0x37, 0x20);
+static SENSOR_DEVICE_ATTR_RO(temp6_min_hyst, min_hyst, 0x55);
+static SENSOR_DEVICE_ATTR_RO(temp6_max_hyst, hyst, 0x54);
+static SENSOR_DEVICE_ATTR_RO(temp6_crit_hyst, hyst, 0x65);
+
+static SENSOR_DEVICE_ATTR_RW(temp7_min, temp, 0x59);
+static SENSOR_DEVICE_ATTR_RW(temp7_max, temp, 0x58);
+static SENSOR_DEVICE_ATTR_RW(temp7_crit, temp, 0x66);
+static SENSOR_DEVICE_ATTR_RO(temp7_input, temp, 0x45);
+static SENSOR_DEVICE_ATTR_2_RO(temp7_fault, bit, 0x1b, 0x40);
+static SENSOR_DEVICE_ATTR_2_RO(temp7_min_alarm, bit, 0x36, 0x40);
+static SENSOR_DEVICE_ATTR_2_RO(temp7_max_alarm, bit, 0x35, 0x40);
+static SENSOR_DEVICE_ATTR_2_RO(temp7_crit_alarm, bit, 0x37, 0x40);
+static SENSOR_DEVICE_ATTR_RO(temp7_min_hyst, min_hyst, 0x59);
+static SENSOR_DEVICE_ATTR_RO(temp7_max_hyst, hyst, 0x58);
+static SENSOR_DEVICE_ATTR_RO(temp7_crit_hyst, hyst, 0x66);
+
+static SENSOR_DEVICE_ATTR_RW(temp8_min, temp, 0x5D);
+static SENSOR_DEVICE_ATTR_RW(temp8_max, temp, 0x5C);
+static SENSOR_DEVICE_ATTR_RW(temp8_crit, temp, 0x67);
+static SENSOR_DEVICE_ATTR_RO(temp8_input, temp, 0x47);
+static SENSOR_DEVICE_ATTR_2_RO(temp8_fault, bit, 0x1b, 0x80);
+static SENSOR_DEVICE_ATTR_2_RO(temp8_min_alarm, bit, 0x36, 0x80);
+static SENSOR_DEVICE_ATTR_2_RO(temp8_max_alarm, bit, 0x35, 0x80);
+static SENSOR_DEVICE_ATTR_2_RO(temp8_crit_alarm, bit, 0x37, 0x80);
+static SENSOR_DEVICE_ATTR_RO(temp8_min_hyst, min_hyst, 0x5D);
+static SENSOR_DEVICE_ATTR_RO(temp8_max_hyst, hyst, 0x5C);
+static SENSOR_DEVICE_ATTR_RO(temp8_crit_hyst, hyst, 0x67);
+
 static SENSOR_DEVICE_ATTR_2_RW(power_state, bit, 0x03, 0x40);
 
 static struct attribute *emc1402_attrs[] = {
@@ -283,6 +331,58 @@  static const struct attribute_group emc1404_group = {
 	.attrs = emc1404_attrs,
 };
 
+static struct attribute *emc1408_attrs[] = {
+	&sensor_dev_attr_temp5_min.dev_attr.attr,
+	&sensor_dev_attr_temp5_max.dev_attr.attr,
+	&sensor_dev_attr_temp5_crit.dev_attr.attr,
+	&sensor_dev_attr_temp5_input.dev_attr.attr,
+	&sensor_dev_attr_temp5_fault.dev_attr.attr,
+	&sensor_dev_attr_temp5_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp5_min_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp5_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp6_min.dev_attr.attr,
+	&sensor_dev_attr_temp6_max.dev_attr.attr,
+	&sensor_dev_attr_temp6_crit.dev_attr.attr,
+	&sensor_dev_attr_temp6_input.dev_attr.attr,
+	&sensor_dev_attr_temp6_fault.dev_attr.attr,
+	&sensor_dev_attr_temp6_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp6_min_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp6_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp6_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp7_min.dev_attr.attr,
+	&sensor_dev_attr_temp7_max.dev_attr.attr,
+	&sensor_dev_attr_temp7_crit.dev_attr.attr,
+	&sensor_dev_attr_temp7_input.dev_attr.attr,
+	&sensor_dev_attr_temp7_fault.dev_attr.attr,
+	&sensor_dev_attr_temp7_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp7_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp7_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp7_min_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp7_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp7_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp8_min.dev_attr.attr,
+	&sensor_dev_attr_temp8_max.dev_attr.attr,
+	&sensor_dev_attr_temp8_crit.dev_attr.attr,
+	&sensor_dev_attr_temp8_input.dev_attr.attr,
+	&sensor_dev_attr_temp8_fault.dev_attr.attr,
+	&sensor_dev_attr_temp8_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp8_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp8_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp8_min_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp8_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp8_crit_hyst.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group emc1408_group = {
+	.attrs = emc1408_attrs,
+};
+
 /*
  * EMC14x2 uses a different register and different bits to report alarm and
  * fault status. For simplicity, provide a separate attribute group for this
@@ -346,6 +446,9 @@  static int emc1403_detect(struct i2c_client *client,
 	case 0x27:
 		strscpy(info->type, "emc1424", I2C_NAME_SIZE);
 		break;
+	case 0x59:
+		strscpy(info->type, "emc1438", I2C_NAME_SIZE);
+		break;
 	case 0x60:
 		strscpy(info->type, "emc1442", I2C_NAME_SIZE);
 		break;
@@ -376,6 +479,14 @@  static bool emc1403_regmap_is_volatile(struct device *dev, unsigned int reg)
 	case 0x35:	/* high limit status */
 	case 0x36:	/* low limit status */
 	case 0x37:	/* therm limit status */
+	case 0x41:	/* external diode 4 high byte */
+	case 0x42:	/* external diode 4 low byte */
+	case 0x43:	/* external diode 5 high byte */
+	case 0x44:	/* external diode 5 low byte */
+	case 0x45:	/* external diode 6 high byte */
+	case 0x46:	/* external diode 6 low byte */
+	case 0x47:	/* external diode 7 high byte */
+	case 0x48:	/* external diode 7 low byte */
 		return true;
 	default:
 		return false;
@@ -409,6 +520,9 @@  static int emc1403_probe(struct i2c_client *client)
 	mutex_init(&data->mutex);
 
 	switch (id->driver_data) {
+	case emc1408:
+		data->groups[3] = &emc1408_group;
+		fallthrough;
 	case emc1404:
 		data->groups[2] = &emc1404_group;
 		fallthrough;
@@ -447,6 +561,7 @@  static const struct i2c_device_id emc1403_idtable[] = {
 	{ "emc1422", emc1402 },
 	{ "emc1423", emc1403 },
 	{ "emc1424", emc1404 },
+	{ "emc1438", emc1408 },
 	{ "emc1442", emc1402 },
 	{ }
 };