ADM1030 Driver

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

 



My comments inline.

> /* Many ADM1030 constants specified below */
> #define ADM1030_CONF1_MEN               0x01 /* monitoring enable */
> #define ADM1030_CONF1_AEN               0x80 /* Auto / SW Control */
> 
> #define ADM1030_REG_FAN_SPEED(nr)   	(0x08 + (nr))
> 
> #define ADM1030_REG_FAN_DIV(nr)		(0x20  + (nr))
> #define ADM1030_REG_FTAC(nr)		(0x10 + (nr))

ADM1030_REG_FAN_LOW or _MIN would be clearer.

> #define ADM1030_REG_FSP(nr)		(0x22 + (nr))

This is not correct, register 0x23 is something different. The normal
speed for fan 2 would obviously be stored in the upper nibble of the
same register. Also, the name isn't very explicit. I'd suggest
ADM1030_REG_FAN_NORMAL_SPEED.

> 
> 
> #define ADM1030_REG_TEMP_HLM(nr)		(0x14  + 4*(nr))
> #define ADM1030_REG_TEMP_LLM(nr)		(0x15  + 4*(nr))
> #define ADM1030_REG_TEMP_TLM(nr)		(0x16  + 4*(nr))

_HIGH, _LOW and (_THERM or _CRIT) prefered.


> /* Temperature values (nr = 1 (local) / 2 (remote)) */
> #define ADM1030_REG_TEMP(nr)		        (0xa + (nr))
> #define ADM1030_REG_TEMP_RNG(nr)		(0x24 + (nr))

RNG is a common acronym for "random number generator". You should use
"RANGE" instead, it's clearer IMHO.

> 
> /* Temperature values (nr = 1 (local) / 2 (remote)) */
> #define ADM1030_REG_CONF(nr)		        (nr)

Comment is bogus. And I don't see the point in using a parameter here,
since the two configuration registers have nothing in common. Just use
two defines.

I also note that the top macros use 0-1 for parameters, while the bottom
ones use 1-2. That's a bit confusing. Isn't it possible to tick to one
single convention?

You aren't taking advantage of the extended temperature resolution bits, are you?

> static u16 adm1030_fan_div = 1;

No. You should not need that, and it wouldn't be safe anymore for the
ADM1031 anyway (unless you declare a second variable). The correct way
to do it is that your to_display_fan_input() macro below should have two
parameters, not one. See asb100.c for a nice example.

> /* Each client has this additional data */
> struct adm1030_data {
>   struct semaphore	update_lock;
>   char			valid;		/* !=0 if following fields are valid */
>   unsigned int		last_updated;	/* In jiffies */
>   unsigned int		fan_input[1];
>   unsigned int	       	fan_div[1];
>   unsigned int	       	pwm[1];
>   unsigned int          temp_input[2];
>   unsigned int          temp_min[2];
>   unsigned int          temp_range[2];
>   unsigned int          temp_low_limit[2];
>   unsigned int          temp_high_limit[2];
>   unsigned int          temp_therm_limit[2];
> };

Indentation is broken.

> /* These macros converts registers values to sysfs-sensors compliant
>  * values
>  */
> #define to_display_temp_low_limit(reg) ((reg) * 1000)
> #define to_display_temp_high_limit(reg) ((reg) * 1000)
> #define to_display_temp_therm_limit(reg) ((reg) * 1000)
> #define to_display_temp_input(reg) ((reg) * 1000)
> #define to_display_temp_min(reg)   (1000 * ((((reg) >> 3) & 0x1f) << 2))
> #define to_display_temp_range(reg) (5000 * (1<<((reg)&0x07)))
> #define to_display_fan_input(reg)  ((reg) ? (11250 * 60) / ((reg)
> *               \
> 						    adm1030_fan_div) : 0)
> #define to_display_fan_div(reg)    (1 << (((reg) & 0xc0)>>6))
> #define to_display_pwm(reg)        ((reg)<<4)

Please use the usual names, see the other drivers for examples. Typical
names are TEMP_FROM_REG, TEMP_TO_REG, etc...

Do not define more macros than you need. For example, you obviously need
a single converter for temperature limits, don't define three.

> /* These macros converts sysfs-sensors compliant values into
>  * corresponding register value.
>  */
> #define to_reg_temp_min(reg, val) ((((val)/500) & 0xf8)|((reg) & 0x7))
> #define to_reg_temp_range(reg, val) (((reg) & 0xf8) | \
> (((val)<10000 ? 0 :                                   \
>   (val)<20000 ? 1 :                                   \
>   (val)<40000 ? 2 :                                   \
>   (val)<80000 ? 3 : 4) & 7))

It just me, or is this macro plain broken?

And usually, converters do not deal with the registers as you do. The
converters should return the "raw" values, and the caller can then
combine these with other values.

> static inline int to_reg_fan_div(unsigned int reg, unsigned int val) 
> {
>   adm1030_fan_div = val;
>   return ((reg & 0x3f) | 
> 	  ((val == 8 ? 0xc0 :                                            
> 	    val == 4 ? 0x80 :                                                
> 	    val == 2 ? 0x40 :                                                
> 	    val == 1 ? 0x00 : reg & 0xc0))); 
> }

Can be simplified.

> #define to_reg_pwm(reg, val) ((val) >> 4)
> #define to_reg_temp_low_limit(reg, val) ((val) / 1000)
> #define to_reg_temp_high_limit(reg, val) ((val) / 1000)
> #define to_reg_temp_therm_limit(reg, val) ((val) / 1000)

See my comments above (no register, no multiple macros doing the same thing).

> #define show(value, nr)	\
> static ssize_t show_##value##_##nr(struct device *dev, char *buf)		\
> {									\
> 	struct adm1030_data *data = adm1030_update_device(dev);		\
> 	return sprintf(buf, "%u\n", to_display_##value(data->value[(nr)-1]));	\
> }
> show(pwm, 1);
> show(temp_min, 1);
> show(temp_min, 2);
> show(temp_low_limit, 1);
> show(temp_low_limit, 2);
> show(temp_high_limit, 1);
> show(temp_high_limit, 2);
> show(temp_therm_limit, 1);
> show(temp_therm_limit, 2);
> show(temp_range, 1);
> show(temp_range, 2);
> show(temp_input, 1);
> show(temp_input, 2);
> show(fan_input, 1);
> show(fan_div, 1);
> 
> #define set(value, reg, nr)	\
> static ssize_t set_##value##_##nr(struct device *dev, const char *buf,
> size_t count)	\
> {								                \
> 	struct i2c_client *client = to_i2c_client(dev);		                \
> 	int temp = simple_strtoul(buf, NULL, 10);		                \
>         int old_val = adm1030_read_value(client,
> reg((nr)-1));                          \
> 	adm1030_write_value(client, reg((nr)-1), to_reg_##value(old_val,
> temp));	\
> 	return count;						                \
> }
> set(temp_min,   ADM1030_REG_TEMP_RNG, 1);
> set(temp_min,   ADM1030_REG_TEMP_RNG, 2);
> set(temp_range, ADM1030_REG_TEMP_RNG, 1);
> set(temp_range, ADM1030_REG_TEMP_RNG, 2);
> set(pwm,        ADM1030_REG_FSP,      1);
> set(fan_div,    ADM1030_REG_FAN_DIV,  1);

Now I get why you were defining multiple macros. You can just pass the
converter as an extra argument to set(). That said, some values will not
fit in that model anyway (set(fan_min...) for example, but strangely you
did not export it?)

> static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input_1, NULL);
> static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input_2, NULL);
> 
> static DEVICE_ATTR(pwm,         S_IWUSR | S_IRUGO, show_pwm_1,
> 		   set_pwm_1);

Incorrect name, should be pwm1.

> static DEVICE_ATTR(fan_div,     S_IRUGO | S_IWUSR, show_fan_div_1,
> 		   set_fan_div_1);

Incorrect name, should be fan1_div.

> static DEVICE_ATTR(fan_input,   S_IRUGO          , show_fan_input_1,   
> 		   NULL);

fan1_input.

Where is fan1_min?

> static DEVICE_ATTR(temp1_amin,   S_IRUGO | S_IWUSR, show_temp_min_1,    
> 		   set_temp_min_1);
> static DEVICE_ATTR(temp1_range, S_IRUGO | S_IWUSR, show_temp_range_1, 
> 		   set_temp_range_1);
> static DEVICE_ATTR(temp2_amin,   S_IRUGO | S_IWUSR, show_temp_min_2,    
> 		   set_temp_min_2);
> static DEVICE_ATTR(temp2_range, S_IRUGO | S_IWUSR, show_temp_range_2,  
> 		   set_temp_range_2);

BTW, what are these ones for? I don't understand why both thermal
sensors have these while there's a single fan to be controled anyway.

Also, I don't much like the names you chose, but you'd have to tell me a
bit more about what it is before I can come to the correct names.

> 	/* Now, we do the remaining detection. It is lousy. */

No, it is *NOT* lousy! (sorry to insist)

> static int adm1030_detach_client(struct i2c_client *client)
> {
> 	i2c_detach_client(client);
> 	kfree(client);
> 	return 0;
> }

You should check for error. The lm75 driver is a bad one and doesn't,
yet should. I think I already mentioned that. See any other chip driver
for an example of how to do it properly.

> 
> static int adm1030_read_value(struct i2c_client *client, u8 reg)
> {
>   return i2c_smbus_read_byte_data(client, reg);
> }
> 
> static int adm1030_write_value(struct i2c_client *client, u8 reg,
> unsigned int value)
> {
>   return i2c_smbus_write_byte_data(client, reg, value);
> }

You do not really need these, do you? At least inline them.

Two general comments/questions now:

1* How does bit 0 of configuration register 2 work? Maybe it could be
exported as pwm1_enable (if that's what it does).

2* I can clearly see that you are preparing the later adding of ADM1031
support. At this point, wouldn't it be easier to really support it? At
least we would protect ourselves against last time bad surprises. (And
if we extend the reasoning a little further, the driver should be named
adm1031, not adm1030, since the adm1030 is clearly a cut-down version of
the adm1031.)

Thanks.


-- 
Jean Delvare
http://www.ensicaen.ismra.fr/~delvare/



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

  Powered by Linux