Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1676747 > unrolled thread
| Started by | Mike Looijmans <mike.looijmans@topic.nl> |
|---|---|
| First post | 2017-06-28 17:00 +0200 |
| Last post | 2017-06-29 10:40 +0200 |
| Articles | 6 — 2 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: [PATCH v2 3/3] hwmon: ltc2990: support all measurement modes Mike Looijmans <mike.looijmans@topic.nl> - 2017-06-28 17:00 +0200
Re: [PATCH v2 3/3] hwmon: ltc2990: support all measurement modes Guenter Roeck <linux@roeck-us.net> - 2017-06-28 17:10 +0200
Re: [PATCH v2 3/3] hwmon: ltc2990: support all measurement modes Guenter Roeck <linux@roeck-us.net> - 2017-06-28 18:10 +0200
Re: [PATCH v2 3/3] hwmon: ltc2990: support all measurement modes Guenter Roeck <linux@roeck-us.net> - 2017-06-28 20:00 +0200
Re: [PATCH v2 3/3] hwmon: ltc2990: support all measurement modes Mike Looijmans <mike.looijmans@topic.nl> - 2017-06-28 20:40 +0200
Re: [PATCH v2 3/3] hwmon: ltc2990: support all measurement modes Mike Looijmans <mike.looijmans@topic.nl> - 2017-06-29 10:40 +0200
| From | Mike Looijmans <mike.looijmans@topic.nl> |
|---|---|
| Date | 2017-06-28 17:00 +0200 |
| Subject | Re: [PATCH v2 3/3] hwmon: ltc2990: support all measurement modes |
| Message-ID | <tXmBJ-86L-29@gated-at.bofh.it> |
On 17-11-16 17:56, Guenter Roeck wrote:
> On 11/17/2016 04:10 AM, Tom Levens wrote:
>> Updated version of the ltc2990 driver which supports all measurement
>> modes available in the chip. The mode can be set through a devicetree
>> attribute.
>
> property
>
>>
>> Signed-off-by: Tom Levens <tom.levens@cern.ch>
>> ---
>>
>> Changes since v1:
>> * Refactored value conversion (patch 1/3)
>> * Split the devicetree binding into separate patch (patch 2/3)
>> * Specifying an invalid mode now returns -EINVAL, previously this
>> only issued a warning and used the default value
>> * Removed the "mode" sysfs attribute, as the mode of the chip is
>> hardware specific and should not be user configurable. This allows much
>> simpler code as a result.
>>
>> Documentation/hwmon/ltc2990 | 24 ++++---
>> drivers/hwmon/Kconfig | 7 +--
>> drivers/hwmon/ltc2990.c | 167 ++++++++++++++++++++++++++++++++++++-------
>> 3 files changed, 159 insertions(+), 39 deletions(-)
>>
>> diff --git a/Documentation/hwmon/ltc2990 b/Documentation/hwmon/ltc2990
>> index c25211e..3ed68f6 100644
>> --- a/Documentation/hwmon/ltc2990
>> +++ b/Documentation/hwmon/ltc2990
>> @@ -8,6 +8,7 @@ Supported chips:
>> Datasheet: http://www.linear.com/product/ltc2990
>>
>> Author: Mike Looijmans <mike.looijmans@topic.nl>
>> + Tom Levens <tom.levens@cern.ch>
>>
>>
>> Description
>> @@ -16,10 +17,8 @@ Description
>> LTC2990 is a Quad I2C Voltage, Current and Temperature Monitor.
>> The chip's inputs can measure 4 voltages, or two inputs together (1+2 and 3+4)
>> can be combined to measure a differential voltage, which is typically used to
>> -measure current through a series resistor, or a temperature.
>> -
>> -This driver currently uses the 2x differential mode only. In order to support
>> -other modes, the driver will need to be expanded.
>> +measure current through a series resistor, or a temperature with an external
>> +diode.
>>
>>
>> Usage Notes
>> @@ -32,12 +31,19 @@ devices explicitly.
>> Sysfs attributes
>> ----------------
>>
>> +in0_input Voltage at Vcc pin in millivolt (range 2.5V to 5V)
>> +temp1_input Internal chip temperature in millidegrees Celcius
>> +
>> +A subset of the following attributes are visible, depending on the measurement
>> +mode of the chip.
>> +
>> +in[1-4]_input Voltage at V[1-4] pin in millivolt
>> +temp2_input External temperature sensor TR1 in millidegrees Celcius
>> +temp3_input External temperature sensor TR2 in millidegrees Celcius
>> +curr1_input Current in mA across V1-V2 assuming a 1mOhm sense resistor
>> +curr2_input Current in mA across V3-V4 assuming a 1mOhm sense resistor
>> +
>> The "curr*_input" measurements actually report the voltage drop across the
>> input pins in microvolts. This is equivalent to the current through a 1mOhm
>> sense resistor. Divide the reported value by the actual sense resistor value
>> in mOhm to get the actual value.
>> -
>> -in0_input Voltage at Vcc pin in millivolt (range 2.5V to 5V)
>> -temp1_input Internal chip temperature in millidegrees Celcius
>> -curr1_input Current in mA across v1-v2 assuming a 1mOhm sense resistor.
>> -curr2_input Current in mA across v3-v4 assuming a 1mOhm sense resistor.
>> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
>> index 45cef3d..f7096ca 100644
>> --- a/drivers/hwmon/Kconfig
>> +++ b/drivers/hwmon/Kconfig
>> @@ -699,15 +699,12 @@ config SENSORS_LTC2945
>> be called ltc2945.
>>
>> config SENSORS_LTC2990
>> - tristate "Linear Technology LTC2990 (current monitoring mode only)"
>> + tristate "Linear Technology LTC2990"
>> depends on I2C
>> help
>> If you say yes here you get support for Linear Technology LTC2990
>> I2C System Monitor. The LTC2990 supports a combination of voltage,
>> - current and temperature monitoring, but in addition to the Vcc supply
>> - voltage and chip temperature, this driver currently only supports
>> - reading two currents by measuring two differential voltages across
>> - series resistors.
>> + current and temperature monitoring.
>>
>> This driver can also be built as a module. If so, the module will
>> be called ltc2990.
>> diff --git a/drivers/hwmon/ltc2990.c b/drivers/hwmon/ltc2990.c
>> index 0ec4102..e8d36f5 100644
>> --- a/drivers/hwmon/ltc2990.c
>> +++ b/drivers/hwmon/ltc2990.c
>> @@ -6,11 +6,7 @@
>> *
>> * License: GPLv2
>> *
>> - * This driver assumes the chip is wired as a dual current monitor, and
>> - * reports the voltage drop across two series resistors. It also reports
>> - * the chip's internal temperature and Vcc power supply voltage.
>> - *
>> - * Value conversion refactored
>> + * Value conversion refactored and support for all measurement modes added
>> * by Tom Levens <tom.levens@cern.ch>
>> */
>>
>> @@ -21,6 +17,7 @@
>> #include <linux/i2c.h>
>> #include <linux/kernel.h>
>> #include <linux/module.h>
>> +#include <linux/of.h>
>>
>> #define LTC2990_STATUS 0x00
>> #define LTC2990_CONTROL 0x01
>> @@ -35,32 +32,96 @@
>> #define LTC2990_CONTROL_KELVIN BIT(7)
>> #define LTC2990_CONTROL_SINGLE BIT(6)
>> #define LTC2990_CONTROL_MEASURE_ALL (0x3 << 3)
>> -#define LTC2990_CONTROL_MODE_CURRENT 0x06
>> -#define LTC2990_CONTROL_MODE_VOLTAGE 0x07
>> +#define LTC2990_CONTROL_MODE_DEFAULT 0x06
>
> I think LTC2990_CONTROL_MODE_CURRENT was better - it describes the actual mode.
> Changing the define to _DEFAULT does not really improve code readability.
>
>> +#define LTC2990_CONTROL_MODE_MAX 0x07
>> +
>> +#define LTC2990_IN0 BIT(0)
>> +#define LTC2990_IN1 BIT(1)
>> +#define LTC2990_IN2 BIT(2)
>> +#define LTC2990_IN3 BIT(3)
>> +#define LTC2990_IN4 BIT(4)
>> +#define LTC2990_CURR1 BIT(5)
>> +#define LTC2990_CURR2 BIT(6)
>> +#define LTC2990_TEMP1 BIT(7)
>> +#define LTC2990_TEMP2 BIT(8)
>> +#define LTC2990_TEMP3 BIT(9)
>> +
>> +static const int ltc2990_attrs_ena[] = {
>> + LTC2990_IN1 | LTC2990_IN2 | LTC2990_TEMP3,
>> + LTC2990_CURR1 | LTC2990_TEMP3,
>> + LTC2990_CURR1 | LTC2990_IN3 | LTC2990_IN4,
>> + LTC2990_TEMP2 | LTC2990_IN3 | LTC2990_IN4,
>> + LTC2990_TEMP2 | LTC2990_CURR2,
>> + LTC2990_TEMP2 | LTC2990_TEMP3,
>> + LTC2990_CURR1 | LTC2990_CURR2,
>> + LTC2990_IN1 | LTC2990_IN2 | LTC2990_IN3 | LTC2990_IN4
>> +};
>> +
>> +struct ltc2990_data {
>> + struct i2c_client *i2c;
>> + u32 mode;
>> +};
>>
>> /* Return the converted value from the given register in uV or mC */
>> -static int ltc2990_get_value(struct i2c_client *i2c, u8 reg, s32 *result)
>> +static int ltc2990_get_value(struct i2c_client *i2c, int index, s32 *result)
>> {
>> s32 val;
>> + u8 reg;
>> +
>> + switch (index) {
>> + case LTC2990_IN0:
>> + reg = LTC2990_VCC_MSB;
>> + break;
>> + case LTC2990_IN1:
>> + case LTC2990_CURR1:
>> + case LTC2990_TEMP2:
>> + reg = LTC2990_V1_MSB;
>> + break;
>> + case LTC2990_IN2:
>> + reg = LTC2990_V2_MSB;
>> + break;
>> + case LTC2990_IN3:
>> + case LTC2990_CURR2:
>> + case LTC2990_TEMP3:
>> + reg = LTC2990_V3_MSB;
>> + break;
>> + case LTC2990_IN4:
>> + reg = LTC2990_V4_MSB;
>> + break;
>> + case LTC2990_TEMP1:
>> + reg = LTC2990_TINT_MSB;
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>>
>> val = i2c_smbus_read_word_swapped(i2c, reg);
>> if (unlikely(val < 0))
>> return val;
>>
>> - switch (reg) {
>> - case LTC2990_TINT_MSB:
>> - /* internal temp, 0.0625 degrees/LSB, 13-bit */
>> + switch (index) {
>> + case LTC2990_TEMP1:
>> + case LTC2990_TEMP2:
>> + case LTC2990_TEMP3:
>> + /* temp, 0.0625 degrees/LSB, 13-bit */
>> *result = sign_extend32(val, 12) * 1000 / 16;
>> break;
>> - case LTC2990_V1_MSB:
>> - case LTC2990_V3_MSB:
>> - /* Vx-Vy, 19.42uV/LSB. Depends on mode. */
>> + case LTC2990_CURR1:
>> + case LTC2990_CURR2:
>> + /* Vx-Vy, 19.42uV/LSB */
>> *result = sign_extend32(val, 14) * 1942 / 100;
>> break;
>> - case LTC2990_VCC_MSB:
>> - /* Vcc, 305.18μV/LSB, 2.5V offset */
>> + case LTC2990_IN0:
>> + /* Vcc, 305.18uV/LSB, 2.5V offset */
>> *result = sign_extend32(val, 14) * 30518 / (100 * 1000) + 2500;
>> break;
>> + case LTC2990_IN1:
>> + case LTC2990_IN2:
>> + case LTC2990_IN3:
>> + case LTC2990_IN4:
>> + /* Vx: 305.18uV/LSB */
>> + *result = sign_extend32(val, 14) * 30518 / (100 * 1000);
>> + break;
>> default:
>> return -EINVAL; /* won't happen, keep compiler happy */
>> }
>> @@ -72,48 +133,104 @@ static ssize_t ltc2990_show_value(struct device *dev,
>> struct device_attribute *da, char *buf)
>> {
>> struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> + struct ltc2990_data *data = dev_get_drvdata(dev);
>> s32 value;
>> int ret;
>>
>> - ret = ltc2990_get_value(dev_get_drvdata(dev), attr->index, &value);
>> + ret = ltc2990_get_value(data->i2c, attr->index, &value);
>> if (unlikely(ret < 0))
>> return ret;
>>
>> return snprintf(buf, PAGE_SIZE, "%d\n", value);
>> }
>>
>> +static umode_t ltc2990_attrs_visible(struct kobject *kobj,
>> + struct attribute *a, int n)
>> +{
>> + struct device *dev = container_of(kobj, struct device, kobj);
>> + struct ltc2990_data *data = dev_get_drvdata(dev);
>> + struct device_attribute *da =
>> + container_of(a, struct device_attribute, attr);
>> + struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> +
>> + if (attr->index == LTC2990_TEMP1 ||
>> + attr->index == LTC2990_IN0 ||
>> + attr->index & ltc2990_attrs_ena[data->mode])
>> + return a->mode;
>> + else
>
> Unnecessary else
>
>> + return 0;
>> +}
>> +
>> static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ltc2990_show_value, NULL,
>> - LTC2990_TINT_MSB);
>> + LTC2990_TEMP1);
>> +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, ltc2990_show_value, NULL,
>> + LTC2990_TEMP2);
>> +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, ltc2990_show_value, NULL,
>> + LTC2990_TEMP3);
>> static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2990_show_value, NULL,
>> - LTC2990_V1_MSB);
>> + LTC2990_CURR1);
>> static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc2990_show_value, NULL,
>> - LTC2990_V3_MSB);
>> + LTC2990_CURR2);
>> static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ltc2990_show_value, NULL,
>> - LTC2990_VCC_MSB);
>> + LTC2990_IN0);
>> +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc2990_show_value, NULL,
>> + LTC2990_IN1);
>> +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc2990_show_value, NULL,
>> + LTC2990_IN2);
>> +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc2990_show_value, NULL,
>> + LTC2990_IN3);
>> +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc2990_show_value, NULL,
>> + LTC2990_IN4);
>>
>> static struct attribute *ltc2990_attrs[] = {
>> &sensor_dev_attr_temp1_input.dev_attr.attr,
>> + &sensor_dev_attr_temp2_input.dev_attr.attr,
>> + &sensor_dev_attr_temp3_input.dev_attr.attr,
>> &sensor_dev_attr_curr1_input.dev_attr.attr,
>> &sensor_dev_attr_curr2_input.dev_attr.attr,
>> &sensor_dev_attr_in0_input.dev_attr.attr,
>> + &sensor_dev_attr_in1_input.dev_attr.attr,
>> + &sensor_dev_attr_in2_input.dev_attr.attr,
>> + &sensor_dev_attr_in3_input.dev_attr.attr,
>> + &sensor_dev_attr_in4_input.dev_attr.attr,
>> NULL,
>> };
>> -ATTRIBUTE_GROUPS(ltc2990);
>> +
>> +static const struct attribute_group ltc2990_group = {
>> + .attrs = ltc2990_attrs,
>> + .is_visible = ltc2990_attrs_visible,
>> +};
>> +__ATTRIBUTE_GROUPS(ltc2990);
>>
>> static int ltc2990_i2c_probe(struct i2c_client *i2c,
>> const struct i2c_device_id *id)
>> {
>> int ret;
>> struct device *hwmon_dev;
>> + struct ltc2990_data *data;
>> + struct device_node *of_node = i2c->dev.of_node;
>>
>> if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
>> I2C_FUNC_SMBUS_WORD_DATA))
>> return -ENODEV;
>>
>> - /* Setup continuous mode, current monitor */
>> + data = devm_kzalloc(&i2c->dev, sizeof(struct ltc2990_data), GFP_KERNEL);
>> + if (unlikely(!data))
>> + return -ENOMEM;
>> + data->i2c = i2c;
>> +
>> + if (!of_node || of_property_read_u32(of_node, "lltc,mode", &data->mode))
>> + data->mode = LTC2990_CONTROL_MODE_DEFAULT;
>
> Iam arguing with myself if we should still do this or if we should read the mode
> from the chip instead if it isn't provided (after all, it may have been
> initialized
> by the BIOS/ROMMON).
>
> Mike, would that break your application, or can you specify the mode in
> devicetree ?
OMFG, I just spent half the day implementing the exact same thing, and only
after sumbmitting it, I stumbled upon this thread. I must be getting old.
A well, seems I implemented things a bit differently, so you get to pick and
choose which patch was better.
Whatever happened to this patch though? It didn't make it to mainline,
otherwise I'd have found it sooner...
>
> Thanks,
> Guenter
>
>> +
>> + if (data->mode > LTC2990_CONTROL_MODE_MAX) {
>> + dev_err(&i2c->dev, "Error: Invalid mode %d.\n", data->mode);
>> + return -EINVAL;
>> + }
>> +
>> + /* Setup continuous mode */
>> ret = i2c_smbus_write_byte_data(i2c, LTC2990_CONTROL,
>> LTC2990_CONTROL_MEASURE_ALL |
>> - LTC2990_CONTROL_MODE_CURRENT);
>> + data->mode);
>> if (ret < 0) {
>> dev_err(&i2c->dev, "Error: Failed to set control mode.\n");
>> return ret;
>> @@ -127,7 +244,7 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c,
>>
>> hwmon_dev = devm_hwmon_device_register_with_groups(&i2c->dev,
>> i2c->name,
>> - i2c,
>> + data,
>> ltc2990_groups);
>>
>> return PTR_ERR_OR_ZERO(hwmon_dev);
>>
>
Kind regards,
Mike Looijmans
System Expert
TOPIC Products
Materiaalweg 4, NL-5681 RJ Best
Postbus 440, NL-5680 AK Best
Telefoon: +31 (0) 499 33 69 79
E-mail: mike.looijmans@topicproducts.com
Website: www.topicproducts.com
Please consider the environment before printing this e-mail
[toc] | [next] | [standalone]
| From | Guenter Roeck <linux@roeck-us.net> |
|---|---|
| Date | 2017-06-28 17:10 +0200 |
| Message-ID | <tXmLp-8q5-63@gated-at.bofh.it> |
| In reply to | #1676747 |
On Wed, Jun 28, 2017 at 04:24:03PM +0200, Mike Looijmans wrote:
> On 17-11-16 17:56, Guenter Roeck wrote:
> >On 11/17/2016 04:10 AM, Tom Levens wrote:
> >>Updated version of the ltc2990 driver which supports all measurement
> >>modes available in the chip. The mode can be set through a devicetree
> >>attribute.
> >
> >property
> >
> >>
> >>Signed-off-by: Tom Levens <tom.levens@cern.ch>
> >>---
> >>
> >>Changes since v1:
> >> * Refactored value conversion (patch 1/3)
> >> * Split the devicetree binding into separate patch (patch 2/3)
> >> * Specifying an invalid mode now returns -EINVAL, previously this
> >> only issued a warning and used the default value
> >> * Removed the "mode" sysfs attribute, as the mode of the chip is
> >> hardware specific and should not be user configurable. This allows much
> >> simpler code as a result.
> >>
> >> Documentation/hwmon/ltc2990 | 24 ++++---
> >> drivers/hwmon/Kconfig | 7 +--
> >> drivers/hwmon/ltc2990.c | 167 ++++++++++++++++++++++++++++++++++++-------
> >> 3 files changed, 159 insertions(+), 39 deletions(-)
> >>
> >>diff --git a/Documentation/hwmon/ltc2990 b/Documentation/hwmon/ltc2990
> >>index c25211e..3ed68f6 100644
> >>--- a/Documentation/hwmon/ltc2990
> >>+++ b/Documentation/hwmon/ltc2990
> >>@@ -8,6 +8,7 @@ Supported chips:
> >> Datasheet: http://www.linear.com/product/ltc2990
> >>
> >> Author: Mike Looijmans <mike.looijmans@topic.nl>
> >>+ Tom Levens <tom.levens@cern.ch>
> >>
> >>
> >> Description
> >>@@ -16,10 +17,8 @@ Description
> >> LTC2990 is a Quad I2C Voltage, Current and Temperature Monitor.
> >> The chip's inputs can measure 4 voltages, or two inputs together (1+2 and 3+4)
> >> can be combined to measure a differential voltage, which is typically used to
> >>-measure current through a series resistor, or a temperature.
> >>-
> >>-This driver currently uses the 2x differential mode only. In order to support
> >>-other modes, the driver will need to be expanded.
> >>+measure current through a series resistor, or a temperature with an external
> >>+diode.
> >>
> >>
> >> Usage Notes
> >>@@ -32,12 +31,19 @@ devices explicitly.
> >> Sysfs attributes
> >> ----------------
> >>
> >>+in0_input Voltage at Vcc pin in millivolt (range 2.5V to 5V)
> >>+temp1_input Internal chip temperature in millidegrees Celcius
> >>+
> >>+A subset of the following attributes are visible, depending on the measurement
> >>+mode of the chip.
> >>+
> >>+in[1-4]_input Voltage at V[1-4] pin in millivolt
> >>+temp2_input External temperature sensor TR1 in millidegrees Celcius
> >>+temp3_input External temperature sensor TR2 in millidegrees Celcius
> >>+curr1_input Current in mA across V1-V2 assuming a 1mOhm sense resistor
> >>+curr2_input Current in mA across V3-V4 assuming a 1mOhm sense resistor
> >>+
> >> The "curr*_input" measurements actually report the voltage drop across the
> >> input pins in microvolts. This is equivalent to the current through a 1mOhm
> >> sense resistor. Divide the reported value by the actual sense resistor value
> >> in mOhm to get the actual value.
> >>-
> >>-in0_input Voltage at Vcc pin in millivolt (range 2.5V to 5V)
> >>-temp1_input Internal chip temperature in millidegrees Celcius
> >>-curr1_input Current in mA across v1-v2 assuming a 1mOhm sense resistor.
> >>-curr2_input Current in mA across v3-v4 assuming a 1mOhm sense resistor.
> >>diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> >>index 45cef3d..f7096ca 100644
> >>--- a/drivers/hwmon/Kconfig
> >>+++ b/drivers/hwmon/Kconfig
> >>@@ -699,15 +699,12 @@ config SENSORS_LTC2945
> >> be called ltc2945.
> >>
> >> config SENSORS_LTC2990
> >>- tristate "Linear Technology LTC2990 (current monitoring mode only)"
> >>+ tristate "Linear Technology LTC2990"
> >> depends on I2C
> >> help
> >> If you say yes here you get support for Linear Technology LTC2990
> >> I2C System Monitor. The LTC2990 supports a combination of voltage,
> >>- current and temperature monitoring, but in addition to the Vcc supply
> >>- voltage and chip temperature, this driver currently only supports
> >>- reading two currents by measuring two differential voltages across
> >>- series resistors.
> >>+ current and temperature monitoring.
> >>
> >> This driver can also be built as a module. If so, the module will
> >> be called ltc2990.
> >>diff --git a/drivers/hwmon/ltc2990.c b/drivers/hwmon/ltc2990.c
> >>index 0ec4102..e8d36f5 100644
> >>--- a/drivers/hwmon/ltc2990.c
> >>+++ b/drivers/hwmon/ltc2990.c
> >>@@ -6,11 +6,7 @@
> >> *
> >> * License: GPLv2
> >> *
> >>- * This driver assumes the chip is wired as a dual current monitor, and
> >>- * reports the voltage drop across two series resistors. It also reports
> >>- * the chip's internal temperature and Vcc power supply voltage.
> >>- *
> >>- * Value conversion refactored
> >>+ * Value conversion refactored and support for all measurement modes added
> >> * by Tom Levens <tom.levens@cern.ch>
> >> */
> >>
> >>@@ -21,6 +17,7 @@
> >> #include <linux/i2c.h>
> >> #include <linux/kernel.h>
> >> #include <linux/module.h>
> >>+#include <linux/of.h>
> >>
> >> #define LTC2990_STATUS 0x00
> >> #define LTC2990_CONTROL 0x01
> >>@@ -35,32 +32,96 @@
> >> #define LTC2990_CONTROL_KELVIN BIT(7)
> >> #define LTC2990_CONTROL_SINGLE BIT(6)
> >> #define LTC2990_CONTROL_MEASURE_ALL (0x3 << 3)
> >>-#define LTC2990_CONTROL_MODE_CURRENT 0x06
> >>-#define LTC2990_CONTROL_MODE_VOLTAGE 0x07
> >>+#define LTC2990_CONTROL_MODE_DEFAULT 0x06
> >
> >I think LTC2990_CONTROL_MODE_CURRENT was better - it describes the actual mode.
> >Changing the define to _DEFAULT does not really improve code readability.
> >
> >>+#define LTC2990_CONTROL_MODE_MAX 0x07
> >>+
> >>+#define LTC2990_IN0 BIT(0)
> >>+#define LTC2990_IN1 BIT(1)
> >>+#define LTC2990_IN2 BIT(2)
> >>+#define LTC2990_IN3 BIT(3)
> >>+#define LTC2990_IN4 BIT(4)
> >>+#define LTC2990_CURR1 BIT(5)
> >>+#define LTC2990_CURR2 BIT(6)
> >>+#define LTC2990_TEMP1 BIT(7)
> >>+#define LTC2990_TEMP2 BIT(8)
> >>+#define LTC2990_TEMP3 BIT(9)
> >>+
> >>+static const int ltc2990_attrs_ena[] = {
> >>+ LTC2990_IN1 | LTC2990_IN2 | LTC2990_TEMP3,
> >>+ LTC2990_CURR1 | LTC2990_TEMP3,
> >>+ LTC2990_CURR1 | LTC2990_IN3 | LTC2990_IN4,
> >>+ LTC2990_TEMP2 | LTC2990_IN3 | LTC2990_IN4,
> >>+ LTC2990_TEMP2 | LTC2990_CURR2,
> >>+ LTC2990_TEMP2 | LTC2990_TEMP3,
> >>+ LTC2990_CURR1 | LTC2990_CURR2,
> >>+ LTC2990_IN1 | LTC2990_IN2 | LTC2990_IN3 | LTC2990_IN4
> >>+};
> >>+
> >>+struct ltc2990_data {
> >>+ struct i2c_client *i2c;
> >>+ u32 mode;
> >>+};
> >>
> >> /* Return the converted value from the given register in uV or mC */
> >>-static int ltc2990_get_value(struct i2c_client *i2c, u8 reg, s32 *result)
> >>+static int ltc2990_get_value(struct i2c_client *i2c, int index, s32 *result)
> >> {
> >> s32 val;
> >>+ u8 reg;
> >>+
> >>+ switch (index) {
> >>+ case LTC2990_IN0:
> >>+ reg = LTC2990_VCC_MSB;
> >>+ break;
> >>+ case LTC2990_IN1:
> >>+ case LTC2990_CURR1:
> >>+ case LTC2990_TEMP2:
> >>+ reg = LTC2990_V1_MSB;
> >>+ break;
> >>+ case LTC2990_IN2:
> >>+ reg = LTC2990_V2_MSB;
> >>+ break;
> >>+ case LTC2990_IN3:
> >>+ case LTC2990_CURR2:
> >>+ case LTC2990_TEMP3:
> >>+ reg = LTC2990_V3_MSB;
> >>+ break;
> >>+ case LTC2990_IN4:
> >>+ reg = LTC2990_V4_MSB;
> >>+ break;
> >>+ case LTC2990_TEMP1:
> >>+ reg = LTC2990_TINT_MSB;
> >>+ break;
> >>+ default:
> >>+ return -EINVAL;
> >>+ }
> >>
> >> val = i2c_smbus_read_word_swapped(i2c, reg);
> >> if (unlikely(val < 0))
> >> return val;
> >>
> >>- switch (reg) {
> >>- case LTC2990_TINT_MSB:
> >>- /* internal temp, 0.0625 degrees/LSB, 13-bit */
> >>+ switch (index) {
> >>+ case LTC2990_TEMP1:
> >>+ case LTC2990_TEMP2:
> >>+ case LTC2990_TEMP3:
> >>+ /* temp, 0.0625 degrees/LSB, 13-bit */
> >> *result = sign_extend32(val, 12) * 1000 / 16;
> >> break;
> >>- case LTC2990_V1_MSB:
> >>- case LTC2990_V3_MSB:
> >>- /* Vx-Vy, 19.42uV/LSB. Depends on mode. */
> >>+ case LTC2990_CURR1:
> >>+ case LTC2990_CURR2:
> >>+ /* Vx-Vy, 19.42uV/LSB */
> >> *result = sign_extend32(val, 14) * 1942 / 100;
> >> break;
> >>- case LTC2990_VCC_MSB:
> >>- /* Vcc, 305.18μV/LSB, 2.5V offset */
> >>+ case LTC2990_IN0:
> >>+ /* Vcc, 305.18uV/LSB, 2.5V offset */
> >> *result = sign_extend32(val, 14) * 30518 / (100 * 1000) + 2500;
> >> break;
> >>+ case LTC2990_IN1:
> >>+ case LTC2990_IN2:
> >>+ case LTC2990_IN3:
> >>+ case LTC2990_IN4:
> >>+ /* Vx: 305.18uV/LSB */
> >>+ *result = sign_extend32(val, 14) * 30518 / (100 * 1000);
> >>+ break;
> >> default:
> >> return -EINVAL; /* won't happen, keep compiler happy */
> >> }
> >>@@ -72,48 +133,104 @@ static ssize_t ltc2990_show_value(struct device *dev,
> >> struct device_attribute *da, char *buf)
> >> {
> >> struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> >>+ struct ltc2990_data *data = dev_get_drvdata(dev);
> >> s32 value;
> >> int ret;
> >>
> >>- ret = ltc2990_get_value(dev_get_drvdata(dev), attr->index, &value);
> >>+ ret = ltc2990_get_value(data->i2c, attr->index, &value);
> >> if (unlikely(ret < 0))
> >> return ret;
> >>
> >> return snprintf(buf, PAGE_SIZE, "%d\n", value);
> >> }
> >>
> >>+static umode_t ltc2990_attrs_visible(struct kobject *kobj,
> >>+ struct attribute *a, int n)
> >>+{
> >>+ struct device *dev = container_of(kobj, struct device, kobj);
> >>+ struct ltc2990_data *data = dev_get_drvdata(dev);
> >>+ struct device_attribute *da =
> >>+ container_of(a, struct device_attribute, attr);
> >>+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> >>+
> >>+ if (attr->index == LTC2990_TEMP1 ||
> >>+ attr->index == LTC2990_IN0 ||
> >>+ attr->index & ltc2990_attrs_ena[data->mode])
> >>+ return a->mode;
> >>+ else
> >
> >Unnecessary else
> >
> >>+ return 0;
> >>+}
> >>+
> >> static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ltc2990_show_value, NULL,
> >>- LTC2990_TINT_MSB);
> >>+ LTC2990_TEMP1);
> >>+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, ltc2990_show_value, NULL,
> >>+ LTC2990_TEMP2);
> >>+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, ltc2990_show_value, NULL,
> >>+ LTC2990_TEMP3);
> >> static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2990_show_value, NULL,
> >>- LTC2990_V1_MSB);
> >>+ LTC2990_CURR1);
> >> static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc2990_show_value, NULL,
> >>- LTC2990_V3_MSB);
> >>+ LTC2990_CURR2);
> >> static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ltc2990_show_value, NULL,
> >>- LTC2990_VCC_MSB);
> >>+ LTC2990_IN0);
> >>+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc2990_show_value, NULL,
> >>+ LTC2990_IN1);
> >>+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc2990_show_value, NULL,
> >>+ LTC2990_IN2);
> >>+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc2990_show_value, NULL,
> >>+ LTC2990_IN3);
> >>+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc2990_show_value, NULL,
> >>+ LTC2990_IN4);
> >>
> >> static struct attribute *ltc2990_attrs[] = {
> >> &sensor_dev_attr_temp1_input.dev_attr.attr,
> >>+ &sensor_dev_attr_temp2_input.dev_attr.attr,
> >>+ &sensor_dev_attr_temp3_input.dev_attr.attr,
> >> &sensor_dev_attr_curr1_input.dev_attr.attr,
> >> &sensor_dev_attr_curr2_input.dev_attr.attr,
> >> &sensor_dev_attr_in0_input.dev_attr.attr,
> >>+ &sensor_dev_attr_in1_input.dev_attr.attr,
> >>+ &sensor_dev_attr_in2_input.dev_attr.attr,
> >>+ &sensor_dev_attr_in3_input.dev_attr.attr,
> >>+ &sensor_dev_attr_in4_input.dev_attr.attr,
> >> NULL,
> >> };
> >>-ATTRIBUTE_GROUPS(ltc2990);
> >>+
> >>+static const struct attribute_group ltc2990_group = {
> >>+ .attrs = ltc2990_attrs,
> >>+ .is_visible = ltc2990_attrs_visible,
> >>+};
> >>+__ATTRIBUTE_GROUPS(ltc2990);
> >>
> >> static int ltc2990_i2c_probe(struct i2c_client *i2c,
> >> const struct i2c_device_id *id)
> >> {
> >> int ret;
> >> struct device *hwmon_dev;
> >>+ struct ltc2990_data *data;
> >>+ struct device_node *of_node = i2c->dev.of_node;
> >>
> >> if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
> >> I2C_FUNC_SMBUS_WORD_DATA))
> >> return -ENODEV;
> >>
> >>- /* Setup continuous mode, current monitor */
> >>+ data = devm_kzalloc(&i2c->dev, sizeof(struct ltc2990_data), GFP_KERNEL);
> >>+ if (unlikely(!data))
> >>+ return -ENOMEM;
> >>+ data->i2c = i2c;
> >>+
> >>+ if (!of_node || of_property_read_u32(of_node, "lltc,mode", &data->mode))
> >>+ data->mode = LTC2990_CONTROL_MODE_DEFAULT;
> >
> >Iam arguing with myself if we should still do this or if we should read the mode
> >from the chip instead if it isn't provided (after all, it may have been
> >initialized
> >by the BIOS/ROMMON).
> >
> >Mike, would that break your application, or can you specify the mode in
> >devicetree ?
>
> OMFG, I just spent half the day implementing the exact same thing, and only
> after sumbmitting it, I stumbled upon this thread. I must be getting old.
>
> A well, seems I implemented things a bit differently, so you get to pick and
> choose which patch was better.
>
As I just replied to your patch, there is no question here. The compatible
statement refers to chip compatibility; one can not use it to also provide
configuration information.
> Whatever happened to this patch though? It didn't make it to mainline,
> otherwise I'd have found it sooner...
>
I'll have to look it up, but I guess I didn't get an updated version.
Guenter
>
> >
> >Thanks,
> >Guenter
> >
> >>+
> >>+ if (data->mode > LTC2990_CONTROL_MODE_MAX) {
> >>+ dev_err(&i2c->dev, "Error: Invalid mode %d.\n", data->mode);
> >>+ return -EINVAL;
> >>+ }
> >>+
> >>+ /* Setup continuous mode */
> >> ret = i2c_smbus_write_byte_data(i2c, LTC2990_CONTROL,
> >> LTC2990_CONTROL_MEASURE_ALL |
> >>- LTC2990_CONTROL_MODE_CURRENT);
> >>+ data->mode);
> >> if (ret < 0) {
> >> dev_err(&i2c->dev, "Error: Failed to set control mode.\n");
> >> return ret;
> >>@@ -127,7 +244,7 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c,
> >>
> >> hwmon_dev = devm_hwmon_device_register_with_groups(&i2c->dev,
> >> i2c->name,
> >>- i2c,
> >>+ data,
> >> ltc2990_groups);
> >>
> >> return PTR_ERR_OR_ZERO(hwmon_dev);
> >>
> >
>
>
>
> Kind regards,
>
> Mike Looijmans
> System Expert
>
> TOPIC Products
> Materiaalweg 4, NL-5681 RJ Best
> Postbus 440, NL-5680 AK Best
> Telefoon: +31 (0) 499 33 69 79
> E-mail: mike.looijmans@topicproducts.com
> Website: www.topicproducts.com
>
> Please consider the environment before printing this e-mail
>
>
>
[toc] | [prev] | [next] | [standalone]
| From | Guenter Roeck <linux@roeck-us.net> |
|---|---|
| Date | 2017-06-28 18:10 +0200 |
| Message-ID | <tXnHs-AC-31@gated-at.bofh.it> |
| In reply to | #1676785 |
On Wed, Jun 28, 2017 at 05:29:38PM +0200, Tom Levens wrote: > [ ... ] > > > >>Whatever happened to this patch though? It didn't make it to mainline, > >>otherwise I'd have found it sooner... > >> > >I'll have to look it up, but I guess I didn't get an updated version. > > As far as I remember I had a working V3 of this patch, but it is entirely > possible that it was never submitted as I have been busy with other projects > recently. I'll dig it out and check that it is complete. > FWIW, I don't see it at https://patchwork.kernel.org/project/linux-hwmon/list/?submitter=171225&state=* Maybe you were waiting for a reply from Rob. Either case, it might make sense to only provide valid modes, ie to abstract the mode bits from the hardware, such as 0 - internal temp only 1 - Tr1 2 - V1 3 - V1-V2 4 - Tr2 5 - V3 6 - V3-V4 7 to 14 - per bit 0..2 Guenter
[toc] | [prev] | [next] | [standalone]
| From | Guenter Roeck <linux@roeck-us.net> |
|---|---|
| Date | 2017-06-28 20:00 +0200 |
| Message-ID | <tXpq4-t5-191@gated-at.bofh.it> |
| In reply to | #1676896 |
On Wed, Jun 28, 2017 at 07:33:33PM +0200, Mike Looijmans wrote: > On 28-06-17 19:02, Tom Levens wrote: > > > >On Wed, 28 Jun 2017, Guenter Roeck wrote: > > > >>On Wed, Jun 28, 2017 at 05:29:38PM +0200, Tom Levens wrote: > >>> > >>[ ... ] > >> > >>>> > >>>>>Whatever happened to this patch though? It didn't make it to mainline, > >>>>>otherwise I'd have found it sooner... > >>>>> > >>>>I'll have to look it up, but I guess I didn't get an updated version. > >>> > >>>As far as I remember I had a working V3 of this patch, but it is > >>>entirely > >>>possible that it was never submitted as I have been busy with other > >>>projects > >>>recently. I'll dig it out and check that it is complete. > >>> > >>FWIW, I don't see it at > >>https://patchwork.kernel.org/project/linux-hwmon/list/?submitter=171225&state=* > >> > >> > >>Maybe you were waiting for a reply from Rob. Either case, it might make > >>sense to only provide valid modes, ie to abstract the mode bits from the > >>hardware, such as > >> > >>0 - internal temp only > >>1 - Tr1 > >>2 - V1 > >>3 - V1-V2 > >>4 - Tr2 > >>5 - V3 > >>6 - V3-V4 > >>7 to 14 - per bit 0..2 > >> > >>Guenter > >> > > > >You are right, there was still an open question about how best to handle > >the mode selection in DT. > > > >In the latest version of my patch I have it implemented as an array for > >setting the two values, for example: > > > > lltc,meas-mode = <7 3>; > > > >This sets bits [2..0] = 7 and [4..3] = 3. Of course these could be split > >into two DT properties, but I was unsure what to name them as both fields > >are called "mode" in the datasheet and "mode-43"/"mode-20" (or similar) is > >ugly. > > > >With regards to your proposal, it is not clear to me whether the modes > >which have the same result are exactly equivalent. Does disabling a > >measurement with the mode[4..3] bits really leaves the part in a safe > >state for all possible HW connections? With this doubt in my head, I would > >prefer to keep the option available to the user to select any specific > >mode. But I am open to suggestions. > > Well, the input restrictions always apply, so disabling V3 measurement > doesn't imply that you can apply 20V to that input safely now. > > I'd suggest to set unused input to plain voltage measurement. That is > "passive" and safe for external components. > > So I'd suggest just setting the mode as per device datasheet, I can see no > real advantage in abstracting it away and forcing users to read yet another > document to get it right, e.g.: > > lltc,mode = <6>; > > As for the input disabling, since I doubt anyone would use it (why purchase > a 4-channel device and use only 2), just add two booleans, e.g. > "disable-inputs-34" and "disable-inputs-12" which set the command bits > appropriately, and change the mode such that the disabled inputs are voltage > readout only. > > A case could even be made for changing mode at runtime. This allows using it > to measure both current and voltage on two inputs, by reading V1, and V3, > and then switch mode to obtain (accurate) V1-V2 and V4-V3. > The hwmon subsystem doesn't really currently support that, and you'll likely confuse userspace as well. > That might be a viable way to handle not setting the mode at all. If the > mode can be selected via sysfs, the driver can keep the device in a "safe" > mode until the mode has been selected. > You'll have to present me with a really good use case for me to agree with that approach. Guenter > > >Mike, if you would like to test it, the latest version of my code is here: > > > >https://github.com/levens/ltc2990/blob/dev/drivers/hwmon/ltc2990.c > > Sure, I even have a board with 2 of these devices now :) > > -- > Mike Looijmans > > > Kind regards, > > Mike Looijmans > System Expert > > TOPIC Products > Materiaalweg 4, NL-5681 RJ Best > Postbus 440, NL-5680 AK Best > Telefoon: +31 (0) 499 33 69 79 > E-mail: mike.looijmans@topicproducts.com > Website: www.topicproducts.com > > Please consider the environment before printing this e-mail > > >
[toc] | [prev] | [next] | [standalone]
| From | Mike Looijmans <mike.looijmans@topic.nl> |
|---|---|
| Date | 2017-06-28 20:40 +0200 |
| Message-ID | <tXpq4-t5-195@gated-at.bofh.it> |
| In reply to | #1676896 |
On 28-06-17 19:02, Tom Levens wrote: > > On Wed, 28 Jun 2017, Guenter Roeck wrote: > >> On Wed, Jun 28, 2017 at 05:29:38PM +0200, Tom Levens wrote: >>> >> [ ... ] >> >>>> >>>>> Whatever happened to this patch though? It didn't make it to mainline, >>>>> otherwise I'd have found it sooner... >>>>> >>>> I'll have to look it up, but I guess I didn't get an updated version. >>> >>> As far as I remember I had a working V3 of this patch, but it is >>> entirely >>> possible that it was never submitted as I have been busy with other >>> projects >>> recently. I'll dig it out and check that it is complete. >>> >> FWIW, I don't see it at >> https://patchwork.kernel.org/project/linux-hwmon/list/?submitter=171225&state=* >> >> >> Maybe you were waiting for a reply from Rob. Either case, it might make >> sense to only provide valid modes, ie to abstract the mode bits from the >> hardware, such as >> >> 0 - internal temp only >> 1 - Tr1 >> 2 - V1 >> 3 - V1-V2 >> 4 - Tr2 >> 5 - V3 >> 6 - V3-V4 >> 7 to 14 - per bit 0..2 >> >> Guenter >> > > You are right, there was still an open question about how best to handle > the mode selection in DT. > > In the latest version of my patch I have it implemented as an array for > setting the two values, for example: > > lltc,meas-mode = <7 3>; > > This sets bits [2..0] = 7 and [4..3] = 3. Of course these could be split > into two DT properties, but I was unsure what to name them as both > fields are called "mode" in the datasheet and "mode-43"/"mode-20" (or > similar) is ugly. > > With regards to your proposal, it is not clear to me whether the modes > which have the same result are exactly equivalent. Does disabling a > measurement with the mode[4..3] bits really leaves the part in a safe > state for all possible HW connections? With this doubt in my head, I > would prefer to keep the option available to the user to select any > specific mode. But I am open to suggestions. Well, the input restrictions always apply, so disabling V3 measurement doesn't imply that you can apply 20V to that input safely now. I'd suggest to set unused input to plain voltage measurement. That is "passive" and safe for external components. So I'd suggest just setting the mode as per device datasheet, I can see no real advantage in abstracting it away and forcing users to read yet another document to get it right, e.g.: lltc,mode = <6>; As for the input disabling, since I doubt anyone would use it (why purchase a 4-channel device and use only 2), just add two booleans, e.g. "disable-inputs-34" and "disable-inputs-12" which set the command bits appropriately, and change the mode such that the disabled inputs are voltage readout only. A case could even be made for changing mode at runtime. This allows using it to measure both current and voltage on two inputs, by reading V1, and V3, and then switch mode to obtain (accurate) V1-V2 and V4-V3. That might be a viable way to handle not setting the mode at all. If the mode can be selected via sysfs, the driver can keep the device in a "safe" mode until the mode has been selected. > Mike, if you would like to test it, the latest version of my code is here: > > https://github.com/levens/ltc2990/blob/dev/drivers/hwmon/ltc2990.c Sure, I even have a board with 2 of these devices now :) -- Mike Looijmans Kind regards, Mike Looijmans System Expert TOPIC Products Materiaalweg 4, NL-5681 RJ Best Postbus 440, NL-5680 AK Best Telefoon: +31 (0) 499 33 69 79 E-mail: mike.looijmans@topicproducts.com Website: www.topicproducts.com Please consider the environment before printing this e-mail
[toc] | [prev] | [next] | [standalone]
| From | Mike Looijmans <mike.looijmans@topic.nl> |
|---|---|
| Date | 2017-06-29 10:40 +0200 |
| Message-ID | <tXD9v-5gl-7@gated-at.bofh.it> |
| In reply to | #1676896 |
On 28-06-17 19:02, Tom Levens wrote: > > On Wed, 28 Jun 2017, Guenter Roeck wrote: > >> On Wed, Jun 28, 2017 at 05:29:38PM +0200, Tom Levens wrote: >>> >> [ ... ] >> >>>> >>>>> Whatever happened to this patch though? It didn't make it to mainline, >>>>> otherwise I'd have found it sooner... >>>>> >>>> I'll have to look it up, but I guess I didn't get an updated version. >>> >>> As far as I remember I had a working V3 of this patch, but it is entirely >>> possible that it was never submitted as I have been busy with other projects >>> recently. I'll dig it out and check that it is complete. >>> >> FWIW, I don't see it at >> https://patchwork.kernel.org/project/linux-hwmon/list/?submitter=171225&state=* >> >> Maybe you were waiting for a reply from Rob. Either case, it might make >> sense to only provide valid modes, ie to abstract the mode bits from the >> hardware, such as >> >> 0 - internal temp only >> 1 - Tr1 >> 2 - V1 >> 3 - V1-V2 >> 4 - Tr2 >> 5 - V3 >> 6 - V3-V4 >> 7 to 14 - per bit 0..2 >> >> Guenter >> > > You are right, there was still an open question about how best to handle the > mode selection in DT. > > In the latest version of my patch I have it implemented as an array for > setting the two values, for example: > > lltc,meas-mode = <7 3>; > > This sets bits [2..0] = 7 and [4..3] = 3. Of course these could be split into > two DT properties, but I was unsure what to name them as both fields are > called "mode" in the datasheet and "mode-43"/"mode-20" (or similar) is ugly. > > With regards to your proposal, it is not clear to me whether the modes which > have the same result are exactly equivalent. Does disabling a measurement with > the mode[4..3] bits really leaves the part in a safe state for all possible HW > connections? With this doubt in my head, I would prefer to keep the option > available to the user to select any specific mode. But I am open to suggestions. > > Mike, if you would like to test it, the latest version of my code is here: > > https://github.com/levens/ltc2990/blob/dev/drivers/hwmon/ltc2990.c > I pulled your patches, added two lines to the devicetree and it works fine, I'm seeing plausible results: root@topic-miami:/sys/class/hwmon# grep . */* hwmon0/name:battery-gauge hwmon0/temp1_input:291700 hwmon1/in0_input:3258 hwmon1/in1_input:1824 hwmon1/in2_input:1916 hwmon1/in3_input:1512 hwmon1/in4_input:2066 hwmon1/name:ltc2990 hwmon1/temp1_input:28062 hwmon1/uevent:OF_NAME=ltc2990 hwmon1/uevent:OF_FULLNAME=/gpios-i2c@50/ltc2990@4c hwmon1/uevent:OF_COMPATIBLE_0=lltc,ltc2990 hwmon1/uevent:OF_COMPATIBLE_N=1 hwmon2/curr1_input:1825 hwmon2/curr2_input:349 hwmon2/in0_input:3244 hwmon2/name:ltc2990 hwmon2/temp1_input:31500 hwmon2/uevent:OF_NAME=ltc2990 hwmon2/uevent:OF_FULLNAME=/gpios-i2c@52/ltc2990@4C hwmon2/uevent:OF_COMPATIBLE_0=ltc2990 hwmon2/uevent:OF_COMPATIBLE_N=1 As you can see, two ltc2990 on two busses, one measuring current and one measuring 4 independent voltages. I also like your implementation of the mode setting better, it's much simpler than mine. And you've solved a bug in the temperature reading as well. Kind regards, Mike Looijmans System Expert TOPIC Products Materiaalweg 4, NL-5681 RJ Best Postbus 440, NL-5680 AK Best Telefoon: +31 (0) 499 33 69 79 E-mail: mike.looijmans@topicproducts.com Website: www.topicproducts.com Please consider the environment before printing this e-mail
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web