two questions about w83792d.c for linux-2.4

Huang0 at Winbond.com.tw Huang0 at Winbond.com.tw
Wed Feb 23 11:28:15 CET 2005


Hi Jean

I have modified the 792 driver again, according to your suggestion.
Would you please check it for me when you are free? :-)

Note that:
(1) All the voltage calculation is done in the driver, the
sensors.conf does NOT use any multiplier for voltage this time.
(2) In the near future, the voltage/fan/temp register macro might
will be combined into such macros as
#define W83781D_REG_IN_MAX(nr) ...
#define W83781D_REG_IN_MIN(nr) ...
#define W83781D_REG_IN(nr) ...
so that I can reduce my codes.


************    related source code    ***************
#define IN_FROM_REG(nr,val) (((nr)<=1)?(val*2): \
                             ( (((nr)==6)||((nr)==7))?(val*6):(val*4) ) )
#define IN_TO_REG(nr,val) (((nr)<=1)?(val/2): \
                           ( (((nr)==6)||((nr)==7))?(val/6):(val/4) ) )

static void w83792d_in(struct i2c_client *client, int operation, int ctl_name,
                        int *nrels_mag, long *results)
{
        struct w83792d_data *data = client->data;
        int nr = ctl_name - W83792D_SYSCTL_IN0;
        u16 vol_max_tmp = 0;
        u16 vol_min_tmp = 0;
        u16 vol_count = 0;
        u16 low_bits = 0;

        /* result[0]: low limit, result[1]: high limit,
           result[2]: current value */
        if (operation == SENSORS_PROC_REAL_INFO)
                *nrels_mag = 3;
        else if (operation == SENSORS_PROC_REAL_READ) {
                w83792d_update_client(client);
                /* Read High/Low limit. */
                vol_min_tmp = data->in_min[nr];
                vol_max_tmp = data->in_max[nr];
                results[0] = IN_FROM_REG(nr, vol_min_tmp*4);
                results[1] = IN_FROM_REG(nr, vol_max_tmp*4);

                /* Read voltage measured value. */
                vol_count = data->in[nr];
                vol_count = (vol_count << 2);
                low_bits = 0;
                switch (nr)
                {
                case 0:  /* vin0 */
                        low_bits = (data->low_bits[0]) & 0x03;
                        break;
                case 1:  /* vin1 */
                        low_bits = ((data->low_bits[0]) & 0x0c) >> 2;
                        break;
                case 2:  /* vin2 */
                        low_bits = ((data->low_bits[0]) & 0x30) >> 4;
                        break;
                case 3:  /* vin3 */
                        low_bits = ((data->low_bits[0]) & 0xc0) >> 6;
                        break;
                case 4:  /* vin4 */
                        low_bits = (data->low_bits[1]) & 0x03;
                        break;
                case 5:  /* vin5 */
                        low_bits = ((data->low_bits[1]) & 0x0c) >> 2;
                        break;
                case 6:  /* vin6 */
                        low_bits = ((data->low_bits[1]) & 0x30) >> 4;
                default:
                        break;
                }
                vol_count = vol_count | low_bits;
                results[2] = IN_FROM_REG(nr, vol_count);
                *nrels_mag = 3;
        } else if (operation == SENSORS_PROC_REAL_WRITE) {
                if( *nrels_mag < 1 ){
                        return;
                }

                /* Write Low limit into register. */
                data->in_min[nr] = SENSORS_LIMIT( IN_TO_REG(nr,results[0])/4,
                                                0, 255 );

                switch (nr)
                {
                case 0:
                        w83792d_write_value(client, W83792D_REG_IN0_MIN,
                                            data->in_min[nr]);
                        break;
                case 1:
                        w83792d_write_value(client, W83792D_REG_IN1_MIN,
                                            data->in_min[nr]);
                        break;
                case 2:
                        w83792d_write_value(client, W83792D_REG_IN2_MIN,
                                            data->in_min[nr]);
                        break;
                case 3:
                        w83792d_write_value(client, W83792D_REG_IN3_MIN,
                                            data->in_min[nr]);
                        break;
                case 4:
                        w83792d_write_value(client, W83792D_REG_IN4_MIN,
                                            data->in_min[nr]);
                        break;
                case 5:
                        w83792d_write_value(client, W83792D_REG_IN5_MIN,
                                            data->in_min[nr]);
                        break;
                case 6:
                        w83792d_write_value(client, W83792D_REG_IN6_MIN,
                                            data->in_min[nr]);
                        break;
                case 7:
                        w83792d_write_value(client, W83792D_REG_IN7_MIN,
                                            data->in_min[nr]);
                        break;
                case 8:
                        w83792d_write_value(client, W83792D_REG_IN8_MIN,
                                            data->in_min[nr]);
                default:
                        break;
                }

                if( *nrels_mag < 2 ){
                        return;
                }
                /* Write High limit into register. */
                data->in_max[nr] = SENSORS_LIMIT( IN_TO_REG(nr,results[1])/4,
                                                0, 255 );
                switch (nr)
                {
                case 0:
                        w83792d_write_value(client, W83792D_REG_IN0_MAX,
                                            data->in_max[nr]);
                        break;
                case 1:
                        w83792d_write_value(client, W83792D_REG_IN1_MAX,
                                            data->in_max[nr]);
                        break;
                case 2:
                        w83792d_write_value(client, W83792D_REG_IN2_MAX,
                                            data->in_max[nr]);
                        break;
                case 3:
                        w83792d_write_value(client, W83792D_REG_IN3_MAX,
                                            data->in_max[nr]);
                        break;
                case 4:
                        w83792d_write_value(client, W83792D_REG_IN4_MAX,
                                            data->in_max[nr]);
                        break;
                case 5:
                        w83792d_write_value(client, W83792D_REG_IN5_MAX,
                                            data->in_max[nr]);
                        break;
                case 6:
                        w83792d_write_value(client, W83792D_REG_IN6_MAX,
                                            data->in_max[nr]);
                        break;
                case 7:
                        w83792d_write_value(client, W83792D_REG_IN7_MAX,
                                            data->in_max[nr]);
                        break;
                case 8:
                        w83792d_write_value(client, W83792D_REG_IN8_MAX,
                                            data->in_max[nr]);
                default:
                        break;
                }
        }
}

********* part of the output of "sensors" *****************
VCoreA:    +1.52 V  (min =  +1.40 V, max =  +1.60 V)
VCoreB:    +1.52 V  (min =  +1.40 V, max =  +1.60 V)
VIN0:      +3.31 V  (min =  +3.20 V, max =  +3.39 V)
VIN1:      +3.18 V  (min =  +3.09 V, max =  +3.30 V)
VIN2:      +1.48 V  (min =  +1.39 V, max =  +1.49 V)
VIN3:      +2.62 V  (min =  +2.59 V, max =  +2.64 V)
5VCC:      +4.96 V  (min =  +4.73 V, max =  +5.23 V)
5VSB:      +4.90 V  (min =  +4.73 V, max =  +5.23 V)
VBAT:      +3.07 V  (min =  +2.85 V, max =  +3.14 V)


***********   voltage interface in /proc    *************
# cat /proc/sys/dev/sensors/w83792d-i2c-0-2f/in*
1.400 1.600 1.508
1.400 1.600 1.516
3.200 3.392 3.296
3.088 3.296 3.180
1.392 1.488 1.476
2.592 2.640 2.612
4.728 5.232 4.956
4.728 5.232 4.896
2.848 3.136 3.072

I have done some small test to it, it seems to work well.:-)


Thanks
Best Regards
Chunhao
2005-02-23



> -----Original Message-----
> From: Jean Delvare [mailto:khali at linux-fr.org]
> Sent: 2005Äê2ÔÂ22ÈÕ 18:23
> To: PI14 HUANG0
> Cc: PI10 LHHsu; PI14 DZSHEN; LM Sensors; PI13 CFLi
> Subject: RE: two questions about w83792d.c for linux-2.4
> 
> 
> Hi Chunhao,
> 
> > Question 1:
> > Need I modify my current calculation method again into your above
> > method?
> 
> Yes please.
> 
> > Is that all the other chip drivers in lm_sensors as what you said:
> > "the values in /proc should really be Volts"? If do, I will try to
> > modify my current method.:-(
> 
> Don't be afraid, it's not that difficult. The difficulty is to get what
> has to be done and understand why. After that, the changes to the code
> should be rather simple.
> 
> > Question 2:
> > I agree that the LSB of in2-5 is 4mV, so as to in2-5, the method you
> > provided is correct. But about in6-in8, you said that their LSB is
> > also 4mV, then how to calculate their measured value? Because in
> > datasheet
> > 5VCC(in6) Voltage = (CR[26]*4 + CR[3F]&0x30) * 0.006;
> > 5VSB(in7) Voltage = CR[B0] * 0.024;
> > VBAT(in8) Voltage = CR[B1] * 0.016;
> > The voltage factor for in6 is 0.006 instead of 0.004, the voltage factor
> > for in7/8 is 0.024/0.016.
> > So I think that I should use the same method as in2-5, and use the
> > multiplier 1.5 in sensors.conf for in6, use the multiplier 6 for
> > in7, and use the multiplier 4 for in8.
> > Am I right? Can you confirm that for me?
> 
> It's a bit more complex than that. First of all, the 0.024 and 0.016
> factors are really (4 * 0.006) and (4 * 0.004), because in7 and in8 do
> not have the additional 2 bits of resolution (exactly the same as the
> limits for all voltages). So in8 is mostly similar to in2-in5 except
> that you have no second register to read:
> in8 = CR[B1] * 4 * 0.004
>     = CR[B1] * 0.016
> 
> For in6-in7, the datasheet explains that they are affected by *internal*
> resistors. This means that you'll really have 5V at the pins, but then
> you have internal resistors right before the ADC (this is needed because
> the max value for the ADC is 4.080V which is less than 5V).
> 
> The reason why these inputs use internal resistors and not external ones
> is that the W83792D itself *needs* the 5V lines as power suppliers. If
> they were attenuated externally it would obviously not work.
> 
> So for in6-in7 the resistors have to be handled inside the driver
> (remember, everything that happens inside the chip belong to the driver,
> everything that happens outside of the chip belong to libsensors). This
> leads to the following in the driver:
> in6 = (CR[26]*4 + ((CR[3F]&0x30)>>4)) * 0.006
> in7 = CR[B0] * 4 * 0.006
>     = CR[B0] * 0.024
> 
> Note that you cannot use floating point in the kernel so you will not
> really multiply by 0.006, 0.016 and 0.024. Instead you multiply by 6, 16
> and 24, and set the "in" file magnitude to 3 (which means divide by
> 1000). This leads to:
> in6 = (CR[26]*4 + ((CR[3F]&0x30)>>4)) * 6;
> in7 = CR[B0] * 24;
> in8 = CR[B1] * 16;
> 
> > Question 3:
> > We discussed the voltage measured value, but how about the voltage
> > limits?
> > I try to get the new calculation method, would you please confirm it?
> > Or please give me the detailed calculation about the voltage limits.
> > VcoreA(in0) Limit = (CR[2B/2C] * 4) * 0.002;
> > VcoreB(in1) Limit = (CR[2D/2E] * 4) * 0.002;
> > VIN0~VIN3(in2-in5) Limit = (CR[2F~36] * 4) * 0.004;
> 
> Looks all OK to me (except that the multipliers are really 2 and 4, with
> magnitude is 3, as explained above).
> 
> > Note: in0-in5 do NOT use any multiplier in sensors.conf
> 
> in0-in1 never will, but in2-in5 may. It all depends on what is wired to
> them, and this choice is left to the motherboard maker. This is the
> exact reason why the multipliers (if any) need to be in sensors.conf and
> not in the driver.
> 
> > 5VCC(in6) Limit = (CR[37/38] * 4) * 0.004;
> > Note: in6 use multiplier 1.5 in sensors.conf, same as the one for
> > in6 measured value.
> >
> > 5VSB(in7) Limit = CR[B4/B5] * 0.004;
> > Note: in7 use multiplier 6 in sensors.conf, same as the one for
> > in7 measured value.
> 
> As explained above, in6 and in7 have internal resistors, so the
> multiplier should be in the driver for these ones.
> 
> > VBAT(in8) Limit = (CR[B6/B7] * 0.004);
> > Note: in8 use multiplier 4 in sensors.conf, same as the one for
> > in8 measured value.
> 
> Not correct, the multiplier 4 must be in the driver, exactly like
> in2-in5. This multiplier is not due to external resistors, but to the
> lack of additional resolution bits.
> 
> I hope I've been clear. I admit it is a bit complicated to get it right
> especially since it is your first driver, and it's a complex one, and
> you're not used to the lm_sensors architecture. The basic rules are:
> 1* The driver must export the voltage _measured at its pins_ to /proc, in
> Volts.
> 2* External resistors are handled by libsensors.
> Rule 1* implies that internal resistors are handled by the driver.
> The second difficulty is that you are not allowed to work with floating
> point values in the kernel, which is why you always multiply by integer
> values and use the magnitude to divide by 10, 100 or 1000 in the end. In
> fact, for the W83792D voltages, you work in millivolts in the driver,
> and the magnitude of 3 divides by 1000 in /proc, resulting in Volts.
> 
> (In Linux 2.6 it has been simplified, /sys handles millivolts too, so
> there is no more magnitude to deal with.)
> 
> Thanks,
> --
> Jean Delvare

===========================================================================================The privileged confidential information contained in this email is intended for use only by the addressees as indicated by the original author of this email. If you are not the addressee indicated in this email or are not responsible for delivery of the email to such person, please kindly reply the sender indicating accordingly and delete all copies of it from your computer and network server immediately. We thank you for your cooperation. It is advisable that any unauthorized use of confidential information of Winbond is strictly prohibited; and any information in this email that does not relate to the official business of Winbond shall be deemed as neither given nor endorsed by Winbond.===========================================================================================If your computer is unable to decode Chinese font, please ignore the following message. They essentially repea!
 t the&nbsp; English statement above.¥»«H¥ó¤º©Ò§tµØ¨¹¹q¤lªº°]²£©Ê¾÷±K©Ê¸ê°T, ¶È±ÂÅv­ìµo«H¤H«ü©w¤§¦¬«H¤H¨ú¾\¤§¥Î. °²¨Ï±z¨Ã«D³Q«ü©w¤§¦¬«H¤H©Î¦]¥ô¦ó­ì¦]¦b¥¼¸g±ÂÅvªº±¡§Î¤§¤U¦¬¨ì¥»«H¥ó, ½Ð±z§iª¾­ìµo«H¤H¨Ã¥ß§Y±N«H¥ó±q¹q¸£»Pºô¸ô¦øªA¾¹¤¤¤©¥H®ø°£. ¹ï©ó±zªº¦X§@, §Ú­Ì¥ý¦¹­PÁÂ. ¯S¦¹´£¿ô, ¥ô¦ó¥¼¸g±ÂÅv¾Õ¦Û¨Ï¥ÎµØ¨¹¹q¤lªº¾÷±K¸ê°Tªº¦æ¬°¬O³QÄY®æ¸T¤îªº. «H¥ó»PµØ¨¹¹q¤lÀç·~µLÃö¤§¤º®e,¤£±oµø¬°µØ¨¹¹q¤l¤§¥ß³õ©Î·N¨£.



More information about the lm-sensors mailing list