Hi Jean, On Mon, Sep 06, 2010 at 12:12:29PM -0400, Jean Delvare wrote: > Hi Guenter, > > On Sat, 4 Sep 2010 15:34:35 -0700, Guenter Roeck wrote: > > Signed-off-by: Guenter Roeck <guenter.roeck@xxxxxxxxxxxx> > > --- > > To apply this patch, the previously submitted lm90 cleanup patch has to be > > applied first. > > > > My main concern with this patch is the chip detection code, specifically if it > > is able to safely distinguish between MAX6680/81 and MAX6695/96. > > Would be great to get some test coverage from a system with one of those chips. > > Unfortunately I don't have any of these Maxim chips at hand. I have an > ADM1032 but it won't offer much coverage obviously. And I have dumps of > Maxim chips, but the real chips behave differently, so it's of little > help. > > Can you please add detection support to sensors-detect as well (and > then update wiki/Devices)? > Sure. I planned to do that after the review is complete, but it makes sense to add it to sensors-detect now. > Review below: > > > > > Sample sensors output: > > > > max6695-i2c-0-19 > > Adapter: SMBus I801 adapter at 5080 > > temp1: +24.5 C (low = -55.0 C, high = +70.0 C) > > (crit = +70.0 C, hyst = +60.0 C) > > temp2: +26.5 C (low = -55.0 C, high = +70.0 C) > > (crit = +90.0 C, hyst = +80.0 C) > > temp3: +24.1 C (low = -54.1 C, high = +70.2 C) > > (crit = +90.0 C, hyst = +80.0 C) > > > > drivers/hwmon/lm90.c | 280 +++++++++++++++++++++++++++++++++++++++++++++----- > > 1 files changed, 252 insertions(+), 28 deletions(-) > > > > diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c > > index aafed28..52ed792 100644 > > --- a/drivers/hwmon/lm90.c > > +++ b/drivers/hwmon/lm90.c > > @@ -42,6 +42,11 @@ > > * chips. The MAX6680 and MAX6681 only differ in the pinout so they can > > * be treated identically. > > * > > + * This driver also supports the MAX6695 and MAX6696, two other sensor > > + * chips made by Maxim. These are also quite similar to other Maxim > > + * chips, but support three temperature sensors instead of two. MAX6695 > > + * and MAX6696 only differ in the pinout so they can be treated identically. > > + * > > Please also update Documentation/hwmon/lm90 and drivers/hwmon/Kconfig. > Ok. > You could also mention the additional emergency temperature limits, as > this is a feature unique to these chips. > Ok. > > * This driver also supports the ADT7461 chip from Analog Devices. > > * It's supported in both compatibility and extended mode. It is mostly > > * compatible with LM90 except for a data format difference for the > > @@ -94,7 +99,7 @@ static const unsigned short normal_i2c[] = { > > 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END }; > > > > enum chips { lm90, adm1032, lm99, lm86, max6657, adt7461, max6680, max6646, > > - w83l771 }; > > + max6695, w83l771 }; > > > > /* > > * The LM90 registers > > @@ -109,6 +114,7 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, adt7461, max6680, max6646, > > #define LM90_REG_R_CONVRATE 0x04 > > #define LM90_REG_W_CONVRATE 0x0A > > #define LM90_REG_R_STATUS 0x02 > > +#define LM90_REG_R_STATUS2 0x12 > > #define LM90_REG_R_LOCAL_TEMP 0x00 > > #define LM90_REG_R_LOCAL_HIGH 0x05 > > #define LM90_REG_W_LOCAL_HIGH 0x0B > > @@ -130,12 +136,16 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, adt7461, max6680, max6646, > > #define LM90_REG_W_REMOTE_LOWH 0x0E > > #define LM90_REG_R_REMOTE_LOWL 0x14 > > #define LM90_REG_W_REMOTE_LOWL 0x14 > > +#define LM90_REG_R_REMOTE_EMERG 0x16 > > +#define LM90_REG_W_REMOTE_EMERG 0x16 > > +#define LM90_REG_R_LOCAL_EMERG 0x17 > > +#define LM90_REG_W_LOCAL_EMERG 0x17 > > #define LM90_REG_R_REMOTE_CRIT 0x19 > > #define LM90_REG_W_REMOTE_CRIT 0x19 > > #define LM90_REG_R_TCRIT_HYST 0x21 > > #define LM90_REG_W_TCRIT_HYST 0x21 > > > > -/* MAX6646/6647/6649/6657/6658/6659 registers */ > > +/* MAX6646/6647/6649/6657/6658/6659/6695/6696 registers */ > > > > #define MAX6657_REG_R_LOCAL_TEMPL 0x11 > > > > @@ -148,6 +158,7 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, adt7461, max6680, max6646, > > * Functions declaration > > */ > > > > +static int lm90_read_reg(struct i2c_client *client, u8 reg, u8 *value); > > static int lm90_detect(struct i2c_client *client, struct i2c_board_info *info); > > static int lm90_probe(struct i2c_client *client, > > const struct i2c_device_id *id); > > @@ -157,6 +168,23 @@ static int lm90_remove(struct i2c_client *client); > > static struct lm90_data *lm90_update_device(struct device *dev); > > > > /* > > + * Some useful macros > > + */ > > +#define lm90_have_offset(data) \ > > + (data->kind != max6657 && data->kind != max6646 \ > > + && data->kind != max6695) > > + > > +#define lm90_have_local_temp_ext(data) \ > > + (data->kind == max6657 || data->kind == max6646 \ > > + || data->kind == max6695) > > + > > +#define lm90_have_remote_limit_ext(data) \ > > + (data->kind != max6657 && data->kind != max6646 \ > > + && data->kind != max6680 && data->kind != max6695) > > + > > +#define lm90_have_emergency(data) (data->kind == max6695) > > Makes the code more readable, I agree, but OTOH it hides complexity. > Such tests are OK during probe or remove, as they happen only once, but > seeing them in runtime code and in particular in the update function, > seems wrong (even though I can't disagree that the overhead is quite > small compared to the cost of SMBus transactions.) > Ultimately, hiding complexity was the reason to introduce the macros. I figured it was better than having the comparisons spread through the code. > I am wondering if it wouldn't be better to use data->flag to carry such > feature information, which would be computed at probe time, once and > for all. What do you think? > > Also, these macros could have been introduced in a separate patch, to > make this one smaller, as they are good to have even without the > max6695/96 support. > Makes sense. I'll do that (using flags) and resubmit as two separate patches. > > + > > +/* > > * Driver data (common to all clients) > > */ > > > > @@ -175,6 +203,8 @@ static const struct i2c_device_id lm90_id[] = { > > { "max6659", max6657 }, > > { "max6680", max6680 }, > > { "max6681", max6680 }, > > + { "max6695", max6695 }, > > + { "max6696", max6695 }, > > { "w83l771", w83l771 }, > > { } > > }; > > @@ -206,20 +236,29 @@ struct lm90_data { > > int flags; > > > > u8 config_orig; /* Original configuration register value */ > > - u8 alert_alarms; /* Which alarm bits trigger ALERT# */ > > + u16 alert_alarms; /* Which alarm bits trigger ALERT# */ > > + /* Upper 8 bits from max6695 STATUS2 register */ > > The comment isn't quite correct. The contents of the STATUS2 register > go to struct member alarms below, not alert_alarms. alert_alarms is set > by the driver at initialization time. > ok > > > > /* registers values */ > > - s8 temp8[4]; /* 0: local low limit > > + s8 temp8[8]; /* 0: local low limit > > 1: local high limit > > 2: local critical limit > > - 3: remote critical limit */ > > - s16 temp11[5]; /* 0: remote input > > + 3: remote critical limit > > + 4: local emergency limit (max6695/96 only) > > + 5: remote emergency limit (max6695/96 only) > > + 6: remote 2 critical limit (max6695/96 only) > > + 7: remote 2 emergency limit (max6695/96 only) */ > > + s16 temp11[8]; /* 0: remote input > > 1: remote low limit > > 2: remote high limit > > - 3: remote offset (except max6646 and max6657) > > - 4: local input */ > > + 3: remote offset (except max6646, max6657/59, > > And 58 too, no? > Correct. > > + and max6695/96) > > + 4: local input > > + 5: remote 2 input (max6695/96 only) > > + 6: remote 2 low limit (max6695/96 only) > > + 7: remote 2 high limit (ma6695/96 only) */ > > u8 temp_hyst; > > - u8 alarms; /* bitvector */ > > + u16 alarms; /* bitvector (upper 8 bits for max6695/96) */ > > }; > > > > /* > > @@ -377,11 +416,15 @@ static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, > > static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, > > const char *buf, size_t count) > > { > > - static const u8 reg[4] = { > > + static const u8 reg[8] = { > > LM90_REG_W_LOCAL_LOW, > > LM90_REG_W_LOCAL_HIGH, > > LM90_REG_W_LOCAL_CRIT, > > LM90_REG_W_REMOTE_CRIT, > > + LM90_REG_W_LOCAL_EMERG, > > + LM90_REG_W_REMOTE_EMERG, > > + LM90_REG_W_REMOTE_CRIT, > > + LM90_REG_W_REMOTE_EMERG, > > }; > > > > struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); > > @@ -390,6 +433,7 @@ static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, > > int nr = attr->index; > > long val; > > int err; > > + u8 config; > > > > err = strict_strtol(buf, 10, &val); > > if (err < 0) > > @@ -406,7 +450,18 @@ static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, > > data->temp8[nr] = temp_to_u8(val); > > else > > data->temp8[nr] = temp_to_s8(val); > > + > > + if (data->kind == max6695 && nr >= 6) { > > + lm90_read_reg(client, LM90_REG_R_CONFIG1, &config); > > + i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, > > + config | 0x08); > > + } > > + > > i2c_smbus_write_byte_data(client, reg[nr], data->temp8[nr]); > > + > > + if (data->kind == max6695 && nr >= 6) > > + i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config); > > + > > mutex_unlock(&data->update_lock); > > return count; > > } > > @@ -450,6 +505,8 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, > > int nr = attr->index; > > long val; > > int err; > > + int offset = 1; > > + u8 config; > > > > err = strict_strtol(buf, 10, &val); > > if (err < 0) > > @@ -462,19 +519,31 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, > > mutex_lock(&data->update_lock); > > if (data->kind == adt7461) > > data->temp11[nr] = temp_to_u16_adt7461(data, val); > > - else if (data->kind == max6657 || data->kind == max6680) > > - data->temp11[nr] = temp_to_s8(val) << 8; > > else if (data->kind == max6646) > > data->temp11[nr] = temp_to_u8(val) << 8; > > + else if (!lm90_have_remote_limit_ext(data)) > > + data->temp11[nr] = temp_to_s8(val) << 8; > > else > > data->temp11[nr] = temp_to_s16(val); > > > > - i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], > > + if (data->kind == max6695 && nr >= 6) { > > + /* select output channel 2 */ > > + lm90_read_reg(client, LM90_REG_R_CONFIG1, &config); > > + i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, > > + config | 0x08); > > + offset = 6; > > + } > > + > > + i2c_smbus_write_byte_data(client, reg[(nr - offset) * 2], > > data->temp11[nr] >> 8); > > This all gets a little tricky... Maybe it is time to rethink the whole > thing. > You mean using the offset variable ? I would agree. No idea right now how to improve it, though. I'll think about it. > > - if (data->kind != max6657 && data->kind != max6680 > > - && data->kind != max6646) > > - i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], > > + if (lm90_have_remote_limit_ext(data)) > > + i2c_smbus_write_byte_data(client, reg[(nr - offset) * 2 + 1], > > data->temp11[nr] & 0xff); > > + > > + if (data->kind == max6695 && nr >= 6) > > + i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, > > + config); > > + > > mutex_unlock(&data->update_lock); > > return count; > > } > > @@ -604,6 +673,62 @@ static const struct attribute_group lm90_group = { > > .attrs = lm90_attributes, > > }; > > > > +/* > > + * Additional attributes for devices with emergency sensors > > + */ > > +static SENSOR_DEVICE_ATTR(temp1_emergency, S_IWUSR | S_IRUGO, show_temp8, > > + set_temp8, 4); > > +static SENSOR_DEVICE_ATTR(temp2_emergency, S_IWUSR | S_IRUGO, show_temp8, > > + set_temp8, 5); > > + > > +/* > > + * Additional attributes for devices with 3 temperature sensors > > + */ > > +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp11, NULL, 5); > > +static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_temp11, > > + set_temp11, 6); > > +static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp11, > > + set_temp11, 7); > > +static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp8, > > + set_temp8, 6); > > +static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); > > +static SENSOR_DEVICE_ATTR(temp3_emergency, S_IWUSR | S_IRUGO, show_temp8, > > + set_temp8, 7); > > + > > +static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 9); > > +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 10); > > +static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_alarm, NULL, 11); > > +static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 12); > > No alarms files for emergency limits? > Actually, there should be. Status register bits are there. No idea why I missed those. Oh well, another ABI change. Is tempX_emergency_alarm ok ? > > + > > +static struct attribute *lm90_emergency_attributes[] = { > > + &sensor_dev_attr_temp1_emergency.dev_attr.attr, > > + &sensor_dev_attr_temp2_emergency.dev_attr.attr, > > + NULL > > +}; > > + > > +static const struct attribute_group lm90_emergency_group = { > > + .attrs = lm90_emergency_attributes, > > +}; > > + > > +static struct attribute *lm90_temp3_attributes[] = { > > + &sensor_dev_attr_temp3_input.dev_attr.attr, > > + &sensor_dev_attr_temp3_min.dev_attr.attr, > > + &sensor_dev_attr_temp3_max.dev_attr.attr, > > + &sensor_dev_attr_temp3_crit.dev_attr.attr, > > + &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, > > + &sensor_dev_attr_temp3_emergency.dev_attr.attr, > > + > > + &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, > > + &sensor_dev_attr_temp3_fault.dev_attr.attr, > > + &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, > > + &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, > > + NULL > > +}; > > + > > +static const struct attribute_group lm90_temp3_group = { > > + .attrs = lm90_temp3_attributes, > > +}; > > + > > /* pec used for ADM1032 only */ > > static ssize_t show_pec(struct device *dev, struct device_attribute *dummy, > > char *buf) > > @@ -688,7 +813,7 @@ static int lm90_detect(struct i2c_client *new_client, > > struct i2c_adapter *adapter = new_client->adapter; > > int address = new_client->addr; > > const char *name = NULL; > > - int man_id, chip_id, reg_config1, reg_convrate; > > + int man_id, chip_id, reg_config1, reg_convrate, reg_emerg; > > > > if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) > > return -ENODEV; > > @@ -704,6 +829,11 @@ static int lm90_detect(struct i2c_client *new_client, > > LM90_REG_R_CONVRATE)) < 0) > > return -ENODEV; > > > > + reg_emerg = i2c_smbus_read_byte_data(new_client, > > + LM90_REG_R_REMOTE_EMERG); > > + if (reg_emerg < 0) > > + return -ENODEV; > > + > > Seems like a rude action, considering that not all supported devices > even have this register. In fact, even reading this register at that > point of the detection is undesirable. At the very least, it will slow > down driver probing for other devices. You should read the register > only on Maxim chips. > Ok, makes sense. Basic idea was that we read chip_id all the time even if the register doesn't exist, and react to it the same way. But you are right, it should only be read for maxim chips. > > if ((address == 0x4C || address == 0x4D) > > && man_id == 0x01) { /* National Semiconductor */ > > int reg_config2; > > @@ -770,6 +900,22 @@ static int lm90_detect(struct i2c_client *new_client, > > name = "max6657"; > > } else > > /* > > + * Even though MAX6695 and MAX6696 do not have a chip ID > > + * register, reading it returns 0x01. > > Regardless of the last read register value? > Unfortunately, yes. I thought the read would return man_id, but it doesn't. > Bad Maxim, they really should learn from their past mistakes. Having a > device ID register really isn't that hard :( > > > Bit 4 of the config1 > > + * register is unused and should return zero when read. > > + * > > + * MAX6695 and MAX6696 have an additional set of temperature > > + * limit registers. We can detect those chips by checking if > > + * one of those registers exists (and thus returns a value > > + * different to the previous reading). > > + */ > > + if (chip_id == 0x01 > > + && (reg_config1 & 0x10) == 0x00 > > + && reg_emerg != reg_convrate > > Note that there is a remote chance that both values are equal even > though the registers are different. Of course this would mean a very > low emergency limit (below 10°C), is this the reason why you're > ignoring this case? > Yes. I'll think about it some more - maybe I find something better. > I'm not even sure what you are trying to protect yourself against. > Given the code flow, the MAX6657/58/59 have already been handled. Are > you aware of other Maxim chips, not handled by the lm90 driver, > behaving the same way? > There is still max6680, tested afterwards. I wanted to make sure as good as I can that I don't detect max6680 as max6695. Of course, who knows what max6680 returns when reading registers 0x16 / 0x17. > > + && reg_convrate <= 0x07) { > > + name = "max6695"; > > + } else > > + /* > > As detection is weak, you may also want to check that bit 0 of status2 > register is 0. Will slow things down a bit but... that's what you get > for poorly identifiable chips. > Ok. Maybe I can read the additional registers only after max6657 was detected. > > * The chip_id register of the MAX6680 and MAX6681 holds the > > * revision of the chip. The lowest bit of the config1 register > > * is unused and should return zero when read, so should the > > @@ -842,6 +988,9 @@ static int lm90_probe(struct i2c_client *new_client, > > case lm86: > > data->alert_alarms = 0x7b; > > break; > > + case max6695: > > + data->alert_alarms = (0x18 << 8) | 0x7c; > > I think 0x187c would be just as readable, wouldn't it? > Yes. > > + break; > > default: > > data->alert_alarms = 0x7c; > > break; > > @@ -854,12 +1003,27 @@ static int lm90_probe(struct i2c_client *new_client, > > err = sysfs_create_group(&new_client->dev.kobj, &lm90_group); > > if (err) > > goto exit_free; > > + > > + if (lm90_have_emergency(data)) { > > + err = sysfs_create_group(&new_client->dev.kobj, > > + &lm90_emergency_group); > > + if (err) > > + goto exit_remove_base; > > + } > > + > > + if (data->kind == max6695) { > > Don't we want lm90_have_temp3(data) or similar for this? > Ok. > > + err = sysfs_create_group(&new_client->dev.kobj, > > + &lm90_temp3_group); > > Please align on opening parenthesis as the rest of the code does. > Sure. > > + if (err) > > + goto exit_remove_emergency; > > + } > > + > > if (new_client->flags & I2C_CLIENT_PEC) { > > err = device_create_file(&new_client->dev, &dev_attr_pec); > > if (err) > > goto exit_remove_files; > > } > > - if (data->kind != max6657 && data->kind != max6646) { > > + if (lm90_have_offset(data)) { > > err = device_create_file(&new_client->dev, > > &sensor_dev_attr_temp2_offset.dev_attr); > > if (err) > > @@ -875,6 +1039,13 @@ static int lm90_probe(struct i2c_client *new_client, > > return 0; > > > > exit_remove_files: > > + if (data->kind == max6695) > > + sysfs_remove_group(&new_client->dev.kobj, &lm90_temp3_group); > > +exit_remove_emergency: > > + if (lm90_have_emergency(data)) > > + sysfs_remove_group(&new_client->dev.kobj, > > + &lm90_emergency_group); > > +exit_remove_base: > > You know, it's always OK to remove files you didn't create, so you > don't have to add these labels. Every error path can basically point to > exit_remove_files. As a matter of fact, dev_attr_pec is created last > and removed last too. > Ok. > > sysfs_remove_group(&new_client->dev.kobj, &lm90_group); > > device_remove_file(&new_client->dev, &dev_attr_pec); > > exit_free: > > @@ -913,6 +1084,12 @@ static void lm90_init_client(struct i2c_client *client) > > if (data->kind == max6680) > > config |= 0x18; > > > > + /* > > + * Select external channel 1 for max6695 > > + */ > > + if (data->kind == max6695) > > + config &= ~0x08; > > + > > config &= 0xBF; /* run */ > > if (config != data->config_orig) /* Only write if changed */ > > i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config); > > @@ -923,9 +1100,13 @@ static int lm90_remove(struct i2c_client *client) > > struct lm90_data *data = i2c_get_clientdata(client); > > > > hwmon_device_unregister(data->hwmon_dev); > > + if (lm90_have_emergency(data)) > > + sysfs_remove_group(&client->dev.kobj, &lm90_emergency_group); > > + if (data->kind == max6695) > > + sysfs_remove_group(&client->dev.kobj, &lm90_temp3_group); > > sysfs_remove_group(&client->dev.kobj, &lm90_group); > > device_remove_file(&client->dev, &dev_attr_pec); > > - if (data->kind != max6657 && data->kind != max6646) > > + if (lm90_have_offset(data)) > > device_remove_file(&client->dev, > > &sensor_dev_attr_temp2_offset.dev_attr); > > BTW, we (you) may want to move all file removal code to a separate > function so that the code can be shared between lm90_probe and > lm90_remove. > Makes sense. I'll check if it also makes sense to put that into a separate patch. > > > > @@ -940,10 +1121,14 @@ static int lm90_remove(struct i2c_client *client) > > static void lm90_alert(struct i2c_client *client, unsigned int flag) > > { > > struct lm90_data *data = i2c_get_clientdata(client); > > - u8 config, alarms; > > + u8 config, alarms, alarms2 = 0; > > > > lm90_read_reg(client, LM90_REG_R_STATUS, &alarms); > > - if ((alarms & 0x7f) == 0) { > > + > > + if (data->kind == max6695) > > + lm90_read_reg(client, LM90_REG_R_STATUS2, &alarms2); > > + > > + if ((alarms & 0x7f) == 0 && (alarms2 & 0xfe) == 0) { > > dev_info(&client->dev, "Everything OK\n"); > > } else { > > if (alarms & 0x61) > > @@ -956,6 +1141,10 @@ static void lm90_alert(struct i2c_client *client, unsigned int flag) > > dev_warn(&client->dev, > > "temp%d diode open, please check!\n", 2); > > > > + if (alarms2 & 0x18) > > + dev_warn(&client->dev, > > + "temp%d out of range, please check!\n", 3); > > + > > /* Disable ALERT# output, because these chips don't implement > > SMBus alert correctly; they should only hold the alert line > > low briefly. */ > > @@ -1011,6 +1200,7 @@ static struct lm90_data *lm90_update_device(struct device *dev) > > if (time_after(jiffies, data->last_updated + HZ / 2 + HZ / 10) > > || !data->valid) { > > u8 h, l; > > + u8 alarms, alarms2 = 0; > > You don't really need alarms, only alarms2. alarms only adds a copy for > all chips, which could be avoided. > You are right. I'll move alarms2 into the max6695 path and keep it local there. > > > > dev_dbg(&client->dev, "Updating lm90 data.\n"); > > lm90_read_reg(client, LM90_REG_R_LOCAL_LOW, &data->temp8[0]); > > @@ -1019,7 +1209,7 @@ static struct lm90_data *lm90_update_device(struct device *dev) > > lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, &data->temp8[3]); > > lm90_read_reg(client, LM90_REG_R_TCRIT_HYST, &data->temp_hyst); > > > > - if (data->kind == max6657 || data->kind == max6646) { > > + if (lm90_have_local_temp_ext(data)) { > > lm90_read16(client, LM90_REG_R_LOCAL_TEMP, > > MAX6657_REG_R_LOCAL_TEMPL, > > &data->temp11[4]); > > @@ -1033,29 +1223,63 @@ static struct lm90_data *lm90_update_device(struct device *dev) > > > > if (lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &h) == 0) { > > data->temp11[1] = h << 8; > > - if (data->kind != max6657 && data->kind != max6680 > > - && data->kind != max6646 > > + if (lm90_have_remote_limit_ext(data) > > && lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL, > > &l) == 0) > > data->temp11[1] |= l; > > } > > if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h) == 0) { > > data->temp11[2] = h << 8; > > - if (data->kind != max6657 && data->kind != max6680 > > - && data->kind != max6646 > > + if (lm90_have_remote_limit_ext(data) > > && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL, > > &l) == 0) > > data->temp11[2] |= l; > > } > > > > - if (data->kind != max6657 && data->kind != max6646) { > > + if (lm90_have_offset(data)) { > > if (lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSH, > > &h) == 0 > > && lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSL, > > &l) == 0) > > data->temp11[3] = (h << 8) | l; > > } > > - lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms); > > + > > + if (data->kind == max6695) { > > + u8 config; > > + > > + lm90_read_reg(client, LM90_REG_R_LOCAL_EMERG, > > + &data->temp8[4]); > > + lm90_read_reg(client, LM90_REG_R_REMOTE_EMERG, > > + &data->temp8[5]); > > These two should be read if (lm90_have_emergency()), as this is the > condition under which the corresponding attributes have been created. > Ok. > > + > > + lm90_read_reg(client, LM90_REG_R_CONFIG1, &config); > > + i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, > > + config | 0x08); > > + > > + lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, > > + &data->temp8[6]); > > + lm90_read_reg(client, LM90_REG_R_REMOTE_EMERG, > > + &data->temp8[7]); > > + lm90_read16(client, LM90_REG_R_REMOTE_TEMPH, > > + LM90_REG_R_REMOTE_TEMPL, &data->temp11[5]); > > + if (!lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &h) > > + && !lm90_read_reg(client, > > + LM90_REG_R_REMOTE_LOWL, &l)) > > + data->temp11[6] = (h << 8) | l; > > + if (!lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h) > > + && !lm90_read_reg(client, > > + LM90_REG_R_REMOTE_HIGHL, &l)) > > + data->temp11[7] = (h << 8) | l; > > Alignment of && is slightly different from what is done in the rest of > the driver. > I'll make sure it matches. > > + > > + i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, > > + config); > > + > > + lm90_read_reg(client, LM90_REG_R_STATUS2, > > + &alarms2); > > + } > > + > > + lm90_read_reg(client, LM90_REG_R_STATUS, &alarms); > > + data->alarms = (alarms2 << 8) | alarms; > > > > /* Re-enable ALERT# output if it was originally enabled and > > * relevant alarms are all clear */ > > Overall it looks pretty good. Too bad these changes are heavily > underlining the design limitations of my driver. It has grown way > beyond what I imagined when writing it, and supports many more devices > with different features than it originally did. > Unfortunately that is true. I was struggling for a while if I should write a separate driver. > If you are motivated to improve the driver's code to be more robust and > readable, feel free, I have no objection! > I'll see if I can do some more cleanup. Thanks a lot for the review! Guenter _______________________________________________ lm-sensors mailing list lm-sensors@xxxxxxxxxxxxxx http://lists.lm-sensors.org/mailman/listinfo/lm-sensors