Re: [PATCH v2] hwmon: (lm85) Add support for EMC6D103S

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Jean,

as always, thanks for the detailed review.

On Fri, 2011-02-25 at 09:43 -0500, Jean Delvare wrote:
> Hi Guenter,
> 
> On Sun, 20 Feb 2011 17:39:12 -0800, Guenter Roeck wrote:
> > EMC6D103S is similar to EMC6D103, only it does not support registers 62[5:7],
> > 6D[0:7], and 6E[0:7]. Register respective sysfs attributes and update affected
> > registers for all other chips only.
> > 
> > Signed-off-by: Guenter Roeck <guenter.roeck@xxxxxxxxxxxx>
> > ---
> > v2: Fix typo in subject
> >     Add EMC66D103 and EMC6D103S to driver documentation
> 
> Can you please update wiki/Devices too?
> 
Done.

> Review:
> 
> > 
> >  Documentation/hwmon/lm85 |   13 ++++++-
> >  drivers/hwmon/lm85.c     |   97 ++++++++++++++++++++++++++++++----------------
> >  2 files changed, 75 insertions(+), 35 deletions(-)
> > 
> > diff --git a/Documentation/hwmon/lm85 b/Documentation/hwmon/lm85
> > index 239258a..0bc9a22 100644
> > --- a/Documentation/hwmon/lm85
> > +++ b/Documentation/hwmon/lm85
> > @@ -26,6 +26,14 @@ Supported chips:
> >      Prefix: 'emc6d102'
> >      Addresses scanned: I2C 0x2c, 0x2d, 0x2e
> >      Datasheet: http://www.smsc.com/main/catalog/emc6d102.html
> > +  * SMSC EMC6D103
> > +    Prefix: 'emc6d103'
> > +    Addresses scanned: I2C 0x2c, 0x2d, 0x2e
> > +    Datasheet: http://www.smsc.com/main/catalog/emc6d103.html
> > +  * SMSC EMC6D103S
> > +    Prefix: 'emc6d103s'
> > +    Addresses scanned: I2C 0x2c, 0x2d, 0x2e
> > +    Datasheet: http://www.smsc.com/main/catalog/emc6d103s.html
> >  
> >  Authors:
> >          Philip Pokorny <ppokorny@xxxxxxxxxxxxxxxxxxxx>,
> > @@ -122,9 +130,12 @@ to be register compatible. The EMC6D100 offers all the features of the
> >  EMC6D101 plus additional voltage monitoring and system control features.
> >  Unfortunately it is not possible to distinguish between the package
> >  versions on register level so these additional voltage inputs may read
> > -zero. The EMC6D102 features addtional ADC bits thus extending precision
> > +zero. EMC6D102 and EMC6D103 feature addtional ADC bits thus extending precision
> >  of voltage and temperature channels.
> >  
> > +SMSC EMC6D103S is similar to EMC6D103, but does not support registers 62[5:7],
> > +6D[0:7], and 6E[0:7]. Respective sysfs attributes (pwmX_auto_pwm_minctl and
> > +tempX_auto_temp_off) are therefore not supported for this chip.
> 
> The documentation being user-oriented, I think it is more valuable to
> document the missing features than the missing registers. The register
> values can be seen in the driver source code for the interested.
> 
Ok.

> If you really insist on documenting the registers, please prefix
> hexadecimal values with 0x for clarity, and drop the [0:7]s which don't
> add value.
> 
I don't.

> Lastly, "not created" would seem more appropriate than "not supported"
> in the last sentence.
> 
> >  
> >  Hardware Configurations
> >  -----------------------
> > diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
> > index d2cc286..d4dd824 100644
> > --- a/drivers/hwmon/lm85.c
> > +++ b/drivers/hwmon/lm85.c
> > @@ -41,7 +41,7 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
> >  enum chips {
> >  	any_chip, lm85b, lm85c,
> >  	adm1027, adt7463, adt7468,
> > -	emc6d100, emc6d102, emc6d103
> > +	emc6d100, emc6d102, emc6d103, emc6d103s
> >  };
> >  
> >  /* The LM85 registers */
> > @@ -352,6 +352,7 @@ static const struct i2c_device_id lm85_id[] = {
> >  	{ "emc6d101", emc6d100 },
> >  	{ "emc6d102", emc6d102 },
> >  	{ "emc6d103", emc6d103 },
> > +	{ "emc6d103s", emc6d103s },
> >  	{ }
> >  };
> >  MODULE_DEVICE_TABLE(i2c, lm85_id);
> > @@ -935,16 +936,18 @@ static ssize_t set_temp_auto_temp_min(struct device *dev,
> >  		| (data->pwm_freq[nr] & 0x07));
> >  
> >  /* Update temp_auto_hyst and temp_auto_off */
> > -	data->zone[nr].hyst = HYST_TO_REG(TEMP_FROM_REG(
> > -		data->zone[nr].limit) - TEMP_FROM_REG(
> > -		data->zone[nr].off_desired));
> > -	if (nr == 0 || nr == 1) {
> > -		lm85_write_value(client, LM85_REG_AFAN_HYST1,
> > -			(data->zone[0].hyst << 4)
> > -			| data->zone[1].hyst);
> > -	} else {
> > -		lm85_write_value(client, LM85_REG_AFAN_HYST2,
> > -			(data->zone[2].hyst << 4));
> > +	if (data->type != emc6d103s) {
> > +		data->zone[nr].hyst = HYST_TO_REG(TEMP_FROM_REG(
> > +			data->zone[nr].limit) - TEMP_FROM_REG(
> > +			data->zone[nr].off_desired));
> > +		if (nr == 0 || nr == 1) {
> > +			lm85_write_value(client, LM85_REG_AFAN_HYST1,
> > +				(data->zone[0].hyst << 4)
> > +				| data->zone[1].hyst);
> > +		} else {
> > +			lm85_write_value(client, LM85_REG_AFAN_HYST2,
> > +				(data->zone[2].hyst << 4));
> > +		}
> >  	}
> 
> This piece of code could probably go away altogether. It tries to be
> smart, but it's bogus. data->zone[nr].off_desired is only initialized
> if set_temp_auto_temp_off() is called, so if set_temp_auto_temp_min()
> is called first, the "off" value will be set improperly.
> 
> It would seem better, and easier, to leave the delta unchanged between
> "min" and "off", until the user sets the "off" value again. This is
> what other drivers do (except that other drivers make it clear that
> this is an hysteresis and not two separate values.)
> 
I removed it.

> >  	mutex_unlock(&data->update_lock);
> >  	return count;
> > @@ -1084,13 +1087,7 @@ static struct attribute *lm85_attributes[] = {
> >  	&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
> >  	&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
> >  	&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
> > -	&sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr,
> > -	&sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr,
> > -	&sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr,
> >  
> > -	&sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr,
> > -	&sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr,
> > -	&sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr,
> >  	&sensor_dev_attr_temp1_auto_temp_min.dev_attr.attr,
> >  	&sensor_dev_attr_temp2_auto_temp_min.dev_attr.attr,
> >  	&sensor_dev_attr_temp3_auto_temp_min.dev_attr.attr,
> > @@ -1111,6 +1108,26 @@ static const struct attribute_group lm85_group = {
> >  	.attrs = lm85_attributes,
> >  };
> >  
> > +static struct attribute *lm85_attributes_minctl[] = {
> > +	&sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr,
> > +	&sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr,
> > +	&sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr,
> > +};
> > +
> > +static const struct attribute_group lm85_group_minctl = {
> > +	.attrs = lm85_attributes_minctl,
> > +};
> > +
> > +static struct attribute *lm85_attributes_temp_off[] = {
> > +	&sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr,
> > +	&sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr,
> > +	&sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr,
> > +};
> > +
> > +static const struct attribute_group lm85_group_temp_off = {
> > +	.attrs = lm85_attributes_temp_off,
> > +};
> > +
> >  static struct attribute *lm85_attributes_in4[] = {
> >  	&sensor_dev_attr_in4_input.dev_attr.attr,
> >  	&sensor_dev_attr_in4_min.dev_attr.attr,
> > @@ -1258,16 +1275,9 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info)
> >  		case LM85_VERSTEP_EMC6D103_A1:
> >  			type_name = "emc6d103";
> >  			break;
> > -		/*
> > -		 * Registers apparently missing in EMC6D103S/EMC6D103:A2
> > -		 * compared to EMC6D103:A0, EMC6D103:A1, and EMC6D102
> > -		 * (according to the data sheets), but used unconditionally
> > -		 * in the driver: 62[5:7], 6D[0:7], and 6E[0:7].
> > -		 * So skip EMC6D103S for now.
> >  		case LM85_VERSTEP_EMC6D103S:
> >  			type_name = "emc6d103s";
> >  			break;
> > -		 */
> >  		}
> >  	} else {
> >  		dev_dbg(&adapter->dev,
> > @@ -1302,6 +1312,7 @@ static int lm85_probe(struct i2c_client *client,
> >  	case emc6d100:
> >  	case emc6d102:
> >  	case emc6d103:
> > +	case emc6d103s:
> >  		data->freq_map = adm1027_freq_map;
> >  		break;
> >  	default:
> > @@ -1319,6 +1330,17 @@ static int lm85_probe(struct i2c_client *client,
> >  	if (err)
> >  		goto err_kfree;
> >  
> > +	/* minctl and temp_off exist on all chips except emc6d103s */
> > +	if (data->type != emc6d103s) {
> > +		err = sysfs_create_group(&client->dev.kobj, &lm85_group_minctl);
> > +		if (err)
> > +			goto err_kfree;
> > +		err = sysfs_create_group(&client->dev.kobj,
> > +					 &lm85_group_temp_off);
> > +		if (err)
> > +			goto err_kfree;
> > +	}
> > +
> >  	/* The ADT7463/68 have an optional VRM 10 mode where pin 21 is used
> >  	   as a sixth digital VID input rather than an analog input. */
> >  	data->vid = lm85_read_value(client, LM85_REG_VID);
> > @@ -1345,6 +1367,8 @@ static int lm85_probe(struct i2c_client *client,
> >  	/* Error out and cleanup code */
> >   err_remove_files:
> >  	sysfs_remove_group(&client->dev.kobj, &lm85_group);
> > +	sysfs_remove_group(&client->dev.kobj, &lm85_group_minctl);
> > +	sysfs_remove_group(&client->dev.kobj, &lm85_group_temp_off);
> >  	sysfs_remove_group(&client->dev.kobj, &lm85_group_in4);
> >  	if (data->type == emc6d100)
> >  		sysfs_remove_group(&client->dev.kobj, &lm85_group_in567);
> 
> For consistency, you should only call sysfs_remove_group for devices
> which need it.
> 
I struggled with what to do here, since in4 is also optional. Should be
clean now.

> > @@ -1358,6 +1382,8 @@ static int lm85_remove(struct i2c_client *client)
> >  	struct lm85_data *data = i2c_get_clientdata(client);
> >  	hwmon_device_unregister(data->hwmon_dev);
> >  	sysfs_remove_group(&client->dev.kobj, &lm85_group);
> > +	sysfs_remove_group(&client->dev.kobj, &lm85_group_minctl);
> > +	sysfs_remove_group(&client->dev.kobj, &lm85_group_temp_off);
> >  	sysfs_remove_group(&client->dev.kobj, &lm85_group_in4);
> >  	if (data->type == emc6d100)
> >  		sysfs_remove_group(&client->dev.kobj, &lm85_group_in567);
> 
> This is calling for a separate function to remove the files, doesn't it?
> 
Done.

> > @@ -1487,7 +1513,8 @@ static struct lm85_data *lm85_update_device(struct device *dev)
> >  			/* More alarm bits */
> >  			data->alarms |= lm85_read_value(client,
> >  						EMC6D100_REG_ALARM3) << 16;
> > -		} else if (data->type == emc6d102 || data->type == emc6d103) {
> > +		} else if (data->type == emc6d102 || data->type == emc6d103 ||
> > +			   data->type == emc6d103s) {
> >  			/* Have to read LSB bits after the MSB ones because
> >  			   the reading of the MSB bits has frozen the
> >  			   LSBs (backward from the ADM1027).
> > @@ -1573,17 +1600,19 @@ static struct lm85_data *lm85_update_device(struct device *dev)
> >  			}
> >  		}
> >  
> > -		i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1);
> > -		data->autofan[0].min_off = (i & 0x20) != 0;
> > -		data->autofan[1].min_off = (i & 0x40) != 0;
> > -		data->autofan[2].min_off = (i & 0x80) != 0;
> > +		if (data->type != emc6d103s) {
> > +			i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1);
> > +			data->autofan[0].min_off = (i & 0x20) != 0;
> > +			data->autofan[1].min_off = (i & 0x40) != 0;
> > +			data->autofan[2].min_off = (i & 0x80) != 0;
> >  
> > -		i = lm85_read_value(client, LM85_REG_AFAN_HYST1);
> > -		data->zone[0].hyst = i >> 4;
> > -		data->zone[1].hyst = i & 0x0f;
> > +			i = lm85_read_value(client, LM85_REG_AFAN_HYST1);
> > +			data->zone[0].hyst = i >> 4;
> > +			data->zone[1].hyst = i & 0x0f;
> >  
> > -		i = lm85_read_value(client, LM85_REG_AFAN_HYST2);
> > -		data->zone[2].hyst = i >> 4;
> > +			i = lm85_read_value(client, LM85_REG_AFAN_HYST2);
> > +			data->zone[2].hyst = i >> 4;
> > +		}
> >  
> >  		data->last_config = jiffies;
> >  	}  /* last_config */
> 
> Other than these minor things, the patch looks sane, and I've tested
> that it causes no regression on my EMC6D102.
> 




_______________________________________________
lm-sensors mailing list
lm-sensors@xxxxxxxxxxxxxx
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors


[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux