Re: [PATCH 1/1] lm73: added 'update_interval' attribute

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

 



On Mon, Dec 24, 2012 at 12:11:09AM -0800, Chris Verges wrote:
> The LM73 supports four A/D conversion resolutions.  The default used by
> the existing lm73 driver is the chip's default, 11-bit (0.25 C/LSB).
> This patch enables changing of this resolution from userspace via the
> temp1_update_interval attribute.
> 
> To change the resolution, write the maximum conversion time as specified
> in the LM73 datasheet for the resolution desired:
> 
>    echo 14  > temp1_update_interval;   # 11-bit, 0.25 C/LSB
>    echo 28  > temp1_update_interval;   # 12-bit, 0.125 C/LSB
>    echo 56  > temp1_update_interval;   # 13-bit, 0.0625 C/LSB
>    echo 112 > temp1_update_interval;   # 14-bit, 0.03125 C/LSB
> 
We'll need to have Documentation/hwmon/lm73 to describe the above.

> In essence, the user can trade off conversion time for increased
> precision.
> 
> Signed-off-by: Chris Verges <kg4ysn@xxxxxxxxx>
> ---
>  drivers/hwmon/lm73.c |   67 +++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 66 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c
> index 7272176..e6c1e05 100644
> --- a/drivers/hwmon/lm73.c
> +++ b/drivers/hwmon/lm73.c
> @@ -39,6 +39,17 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c,
>  #define LM73_TEMP_MIN		(-40)
>  #define LM73_TEMP_MAX		150
>  
> +#define LM73_CTRL_RES_OFFSET	(5)
> +#define LM73_CTRL_RES_SIZE	(2)

Unnecessary ( )
Maybe LM73_CTRL_RES_SHIFT instead of LM73_CTRL_RES_OFFSET would be better.

> +#define LM73_CTRL_RES_MASK	((1 << LM73_CTRL_RES_SIZE) - 1)
> +
> +static long lm73_valid_convrates[] = {

int or even u16 would be sufficient.

> +	14,	/* 11-bits (0.25000 C/LSB): RES1 Bit = 0, RES0 Bit = 0 */
> +	28,	/* 12-bits (0.12500 C/LSB): RES1 Bit = 0, RES0 Bit = 1 */
> +	56,	/* 13-bits (0.06250 C/LSB): RES1 Bit = 1, RES0 Bit = 0 */
> +	112,	/* 14-bits (0.03125 C/LSB): RES1 Bit = 1, RES0 Bit = 1 */
> +};
> +
>  /*-----------------------------------------------------------------------*/
>  
>  
> @@ -79,6 +90,58 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *da,
>  	return scnprintf(buf, PAGE_SIZE, "%d\n", temp);
>  }
>  
> +static ssize_t set_convrate(struct device *dev, struct device_attribute *da,
> +			    const char *buf, size_t count)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> +	struct i2c_client *client = to_i2c_client(dev);
> +	long convrate;
> +	uint32_t ctrl;
> +	u8 res_bits = 0;
> +	u8 value;
> +	u32 err;

Be careful with variable types. u32 and uint32_t wil never be negative. And
please don't mix the types like you do here. But then both need to be int
anyway.

> +
> +	int status = kstrtol(buf, 10, &convrate);
> +	if (status < 0)
> +		return status;
> +
Negative values don't make much sense here, so unsigned long and kstrtoul might
be better. And you don't need both status and err variables; I'd suggest to go
with err.

> +	/* Validate the accepted conversion rate */
> +	while (res_bits < ARRAY_SIZE(lm73_valid_convrates) && lm73_valid_convrates[res_bits] != convrate)

Line length

> +		res_bits++;
> +
You'll want to check for ranges here, eg accept everything from 0 .. 21 to 14,
everything from 21 .. (28 + 56) / 2 to 28 and so on.

> +	if (res_bits >= ARRAY_SIZE(lm73_valid_convrates))
> +		return -EINVAL;
> +
> +	/* Read existing control value */
> +	ctrl = i2c_smbus_read_byte_data(client, attr->index);

Please use LM73_REG_CTRL directly.

> +	if (ctrl < 0)
> +		return ctrl;

ctrl is uint32_t and thus never negative. Needs to be int.

> +
> +	/* Write value */
> +	value = ctrl;

Just define ctrl as int and use it. No need for a separate variable.

> +	value &= ~(LM73_CTRL_RES_MASK << LM73_CTRL_RES_OFFSET);
> +	value |= ((res_bits & LM73_CTRL_RES_MASK) << LM73_CTRL_RES_OFFSET);

res_bits will never be larger than the mask, so no need to mask it here.

> +	err = i2c_smbus_write_byte_data(client, attr->index, value);
> +	return (err < 0) ? err : count;

I personally prefer 
	if (err < 0)
		return err;
	return count;
as less confusing. But if you do it fancy, you might as well use

	return (err < 0) ? : count;

> +}
> +
> +static ssize_t show_convrate(struct device *dev, struct device_attribute *da,
> +			     char *buf)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> +	struct i2c_client *client = to_i2c_client(dev);
> +	uint32_t ctrl;
> +	u8 res_bits = 0;
> +
> +	/* Read existing control value */
> +	ctrl = i2c_smbus_read_byte_data(client, attr->index);

You can use LM73_REG_CTRL directly here. Using the ->index variable only
makes sense if there are multiple functions accessing different registers with
the same code.

> +	if (ctrl < 0)
> +		return ctrl;

You defined ctrl as uint32_t, so it will never be negative.

> +
> +	res_bits = (ctrl & ~LM73_CTRL_RES_MASK) >> LM73_CTRL_RES_OFFSET;

		= (ctrl >> LM73_CTRL_RES_OFFSET) & LM73_CTRL_RES_MASK;

> +	return scnprintf(buf, PAGE_SIZE, "%u\n", res_bits);

Need to convert to ms.
	return scnprintf(buf, PAGE_SIZE, "%ld\n", lm73_valid_convrates[res_bits]);

or %d / %u depending on the type of lm73_valid_convrates.

> +}
> +
>  
One empty line is enough.

>  /*-----------------------------------------------------------------------*/
>  
> @@ -90,13 +153,15 @@ static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
>  			show_temp, set_temp, LM73_REG_MIN);
>  static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
>  			show_temp, NULL, LM73_REG_INPUT);
> +static SENSOR_DEVICE_ATTR(temp1_update_interval, S_IWUSR | S_IRUGO,
> +			show_convrate, set_convrate, LM73_REG_CTRL);
>  
>  
>  static struct attribute *lm73_attributes[] = {
>  	&sensor_dev_attr_temp1_input.dev_attr.attr,
>  	&sensor_dev_attr_temp1_max.dev_attr.attr,
>  	&sensor_dev_attr_temp1_min.dev_attr.attr,
> -
> +	&sensor_dev_attr_temp1_update_interval.dev_attr.attr,
>  	NULL
>  };
>  
> -- 
> 1.7.9.5
> 
> 

_______________________________________________
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