Changeset 2453

Show
Ignore:
Timestamp:
04/19/04 21:46:14 (5 years ago)
Author:
khali
Message:

Support voltages and temperatures of National Semiconductor

PC87365 and PC87366 (read-only).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • lm-sensors/trunk/doc/chips/SUMMARY

    r2444 r2453  
    159159        pc87363         -       -       2       2 pwm   no      yes (LPC) 
    160160        pc87364         -       -       3       3 pwm   no      yes (LPC) 
    161         pc87365         -      -      3       3 pwm   no      yes (LPC) 
    162         pc87366         -      -      3       3 pwm   no      yes (LPC) 
     161        pc87365         2      11     3       3 pwm   no      yes (LPC) 
     162        pc87366         3      11     3       3 pwm   no      yes (LPC) 
    163163 
    164164sis5595 
  • lm-sensors/trunk/doc/chips/pc87360

    r2427 r2453  
    3333hardware monitoring chipsets, not only controling and monitoring three fans, 
    3434but also monitoring eleven voltage inputs and two (PC87365) or three 
    35 (PC87366) remote temperatures. For now, the driver doesn't handle these 
    36 features and treat these two chips as PC87364. 
     35(PC87366) remote temperatures. 
    3736 
    3837Fan rotation speeds are reported in RPM (revolutions per minute). An alarm 
     
    4847PWM values are from 0 to 255. 
    4948 
     49Temperatures are reported in degrees Celcius. Each temperature measured has 
     50associated low limit, high limit and overtemperature limit, each of which 
     51triggers an alarm when crossed. 
     52 
     53Voltages are reported relatively to a relative voltage, either internal or 
     54external. Some of them are divided by two internally, you will have to 
     55compensate in sensors.conf. Each voltage measured has associated low and 
     56high limit, each of which triggers an alarm when crossed. 
     57 
    5058If an alarm triggers, it will remain triggered until the hardware register 
    5159is read at least once. This means that the cause for the alarm may  
     
    5967----------- 
    6068 
    61 This driver only supports fans at the moment. 
     69The voltages and temperatures are read-only at the moment. 
    6270 
    6371The datasheets suggests that some values (fan mins, fan divisors) 
  • lm-sensors/trunk/kernel/chips/pc87360.c

    r2445 r2453  
    4545static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; 
    4646static u8 devid; 
     47static unsigned int extra_isa[] = { 0x0000, 0x0000, 0x0000 }; 
    4748 
    4849SENSORS_INSMOD_5(pc87360, pc87363, pc87364, pc87365, pc87366); 
    4950 
    50 /* modified from kernel/include/traps.c */ 
     51/* 
     52 * Super-I/O registers and operations 
     53 */ 
     54 
    5155#define REG     0x2e    /* The register to read/write */ 
     56#define VAL     0x2f    /* The value to read/write */ 
     57 
    5258#define DEV     0x07    /* Register: Logical device select */ 
    53 #define VAL     0x2f    /* The value to read/write */ 
    54 #define FSCM    0x09    /* The device with the fan registers in it */ 
    5559#define DEVID   0x20    /* Register: Device ID */ 
     60#define ACT     0x30    /* Register: Device activation */ 
     61#define BASE    0x60    /* Register: Base address */ 
     62 
     63#define FSCM    0x09    /* Logical device: fans */ 
     64#define VLM     0x0d    /* Logical device: voltages */ 
     65#define TMS     0x0e    /* Logical device: temperatures */ 
     66static const u8 logdev[3] = { FSCM, VLM, TMS }; 
    5667 
    5768static inline void superio_outb(int reg, int val) 
     
    6778} 
    6879 
    69 static inline void superio_select(void) 
    70 { 
    71         outb(DEV, REG); 
    72         outb(FSCM, VAL); 
    73 } 
    74  
    7580static inline void superio_exit(void) 
    7681{ 
     
    7984} 
    8085 
     86#define PC87360_EXTENT          0x10 
     87 
    8188/* 
    82  * The PC87360 (device id 0xE1) and PC87363 (device id 0xE8) monitor and 
    83  * control two fans. 
    84  * The PC87364 (device id 0xE4), PC87365 (device id 0xE5) and PC87366 
    85  * (device id 0xE9) monitor and control three fans. 
     89 * Fan registers and conversions 
    8690 */ 
    87 #define PC87360_DEVID_MATCH(id) ((id) == 0xE1 || (id) == 0xE8 || \ 
    88                                  (id) == 0xE4 || (id) == 0xE5 || \ 
    89                                  (id) == 0xE9) 
    90  
    91 #define PC87360_BASE_REG        0x60 
    92 #define PC87360_ACTIVATE_REG    0x30 
    93  
    94 #define PC87360_EXTENT          0x10 
    9591 
    9692/* nr has to be 0 or 1 (PC87360/87363) or 2 (PC87364/87365/87366) */ 
     
    10197#define PC87360_REG_FAN_STATUS(nr)      (0x08 + 3 * (nr)) 
    10298 
    103 #define FAN_FROM_REG(val,div)   ((val)==0?-1:(val)==255?0: \ 
    104                                  960000/((val)*(div))) 
    105 #define FAN_TO_REG(val,div)     ((val)<=0?255: \ 
    106                                  960000/((val)*(div))) 
    107 #define FAN_DIV_FROM_REG(val)   (1 << ((val >> 5) & 0x03)) 
    108 #define FAN_DIV_TO_REG(val)     ((val)==8?0x60:(val)==4?0x40:(val)==1?0x00:0x20) 
    109 #define ALARM_FROM_REG(val)     ((val) & 0x07) 
     99#define FAN_FROM_REG(val,div)           ((val)==0?-1:(val)==255?0: \ 
     100                                         960000/((val)*(div))) 
     101#define FAN_TO_REG(val,div)             ((val)<=0?255: \ 
     102                                         960000/((val)*(div))) 
     103#define FAN_DIV_FROM_REG(val)           (1 << ((val >> 5) & 0x03)) 
     104#define FAN_DIV_TO_REG(val)             ((val)==8?0x60:(val)==4?0x40:(val)==1?0x00:0x20) 
     105#define FAN_STATUS_FROM_REG(val)        ((val) & 0x07) 
     106 
     107/* 
     108 * Voltage registers and conversions 
     109 */ 
     110 
     111#define PC87365_REG_IN_BANK             0x09 
     112 
     113/* nr has to be 0 to 11 (PC87365/87366) */ 
     114#define PC87365_REG_IN                  0x0B 
     115#define PC87365_REG_IN_MIN              0x0D 
     116#define PC87365_REG_IN_MAX              0x0C 
     117#define PC87365_REG_IN_STATUS           0x0A 
     118#define PC87365_REG_IN_ALARMS1          0x00 
     119#define PC87365_REG_IN_ALARMS2          0x01 
     120 
     121#define IN_FROM_REG(val)                (((val) * 2967 + 127) / 255) 
     122#define IN_STATUS_FROM_REG(val)         ((val) & 0x86) 
     123 
     124/* 
     125 * Temperature registers and conversions 
     126 */ 
     127 
     128#define PC87365_REG_TEMP_BANK           0x09 
     129 
     130/* nr has to be 0 to 1 (PC87365) or 2 (PC87366) */ 
     131#define PC87365_REG_TEMP                0x0B 
     132#define PC87365_REG_TEMP_MIN            0x0D 
     133#define PC87365_REG_TEMP_MAX            0x0C 
     134#define PC87365_REG_TEMP_CRIT           0x0D 
     135#define PC87365_REG_TEMP_STATUS         0x0A 
     136#define PC87365_REG_TEMP_ALARMS         0x00 
     137 
     138#define TEMP_FROM_REG(val)              ((val)&0x80 ? (val) : (val) - 128) 
     139#define TEMP_STATUS_FROM_REG(val)       ((val) & 0xCE) 
    110140 
    111141struct pc87360_data { 
     
    113143        struct semaphore lock; 
    114144        int sysctl_id; 
     145        int address[3]; 
    115146 
    116147        struct semaphore update_lock; 
     
    118149        unsigned long last_updated;     /* In jiffies */ 
    119150 
    120         u8 fannr
     151        u8 fannr, innr, tempnr
    121152 
    122153        u8 fan[3];              /* Register value */ 
     
    124155        u8 fan_status[3];       /* Register value */ 
    125156        u8 pwm[3];              /* Register value */ 
     157 
     158        u8 in[11];              /* Register value */ 
     159        u8 in_min[11];          /* Register value */ 
     160        u8 in_max[11];          /* Register value */ 
     161        u8 in_status[11];       /* Register value */ 
     162        u16 in_alarms;          /* Register values, combined */ 
     163 
     164        u8 temp[3];             /* Register value */ 
     165        u8 temp_min[3];         /* Register value */ 
     166        u8 temp_max[3];         /* Register value */ 
     167        u8 temp_crit[3];        /* Register value */ 
     168        u8 temp_status[3];      /* Register value */ 
     169        u8 temp_alarms;         /* Register value */ 
    126170}; 
    127171 
     
    132176static int pc87360_detach_client(struct i2c_client *client); 
    133177 
    134 static int pc87360_read_value(struct i2c_client *client, u8 register); 
    135 static int pc87360_write_value(struct i2c_client *client, u8 register
     178static int pc87360_read_value(struct pc87360_data *data, int ldi, u8 reg); 
     179static int pc87360_write_value(struct pc87360_data *data, int ldi, u8 reg
    136180                               u8 value); 
    137181static void pc87360_update_client(struct i2c_client *client); 
    138 static void pc87360_init_client(struct i2c_client *client); 
    139 static int pc87360_find(int *address, u8 *devid); 
    140  
     182static int pc87360_find(u8 *devid, int *address); 
     183 
     184 
     185void pc87365_alarms(struct i2c_client *client, int operation, int ctl_name, 
     186                    int *nrels_mag, long *results); 
    141187 
    142188static void pc87360_fan(struct i2c_client *client, int operation, 
     
    149195                        int ctl_name, int *nrels_mag, long *results); 
    150196 
     197void pc87365_in(struct i2c_client *client, int operation, int ctl_name, 
     198                int *nrels_mag, long *results); 
     199void pc87365_in_status(struct i2c_client *client, int operation, int ctl_name, 
     200                       int *nrels_mag, long *results); 
     201 
     202void pc87365_temp(struct i2c_client *client, int operation, int ctl_name, 
     203                  int *nrels_mag, long *results); 
     204void pc87365_temp_status(struct i2c_client *client, int operation, int ctl_name, 
     205                         int *nrels_mag, long *results); 
     206 
    151207static int pc87360_id = 0; 
    152208 
     
    160216 
    161217/* -- SENSORS SYSCTL START -- */ 
     218 
     219#define PC87365_SYSCTL_ALARMS           100 /* bit field */ 
    162220 
    163221#define PC87360_SYSCTL_FAN1             1101 /* Rotations/min */ 
     
    172230#define PC87360_SYSCTL_PWM3             1403 /* not for PC87360/PC87363 */ 
    173231 
    174 #define PC87360_ALARM_FAN_READY         0x01 
    175 #define PC87360_ALARM_FAN_LOW           0x02 
    176 #define PC87360_ALARM_FAN_OVERFLOW      0x04 
     232#define PC87360_STATUS_FAN_READY        0x01 
     233#define PC87360_STATUS_FAN_LOW          0x02 
     234#define PC87360_STATUS_FAN_OVERFLOW     0x04 
     235 
     236#define PC87365_SYSCTL_IN0              2100 /* mV */ 
     237#define PC87365_SYSCTL_IN1              2101 
     238#define PC87365_SYSCTL_IN2              2102 
     239#define PC87365_SYSCTL_IN3              2103 
     240#define PC87365_SYSCTL_IN4              2104 
     241#define PC87365_SYSCTL_IN5              2105 
     242#define PC87365_SYSCTL_IN6              2106 
     243#define PC87365_SYSCTL_IN7              2107 
     244#define PC87365_SYSCTL_IN8              2108 
     245#define PC87365_SYSCTL_IN9              2109 
     246#define PC87365_SYSCTL_IN10             2110 
     247#define PC87365_SYSCTL_IN0_STATUS       2300 /* bit field */ 
     248#define PC87365_SYSCTL_IN1_STATUS       2301 
     249#define PC87365_SYSCTL_IN2_STATUS       2302 
     250#define PC87365_SYSCTL_IN3_STATUS       2303 
     251#define PC87365_SYSCTL_IN4_STATUS       2304 
     252#define PC87365_SYSCTL_IN5_STATUS       2305 
     253#define PC87365_SYSCTL_IN6_STATUS       2306 
     254#define PC87365_SYSCTL_IN7_STATUS       2307 
     255#define PC87365_SYSCTL_IN8_STATUS       2308 
     256#define PC87365_SYSCTL_IN9_STATUS       2309 
     257#define PC87365_SYSCTL_IN10_STATUS      2310 
     258 
     259#define PC87365_STATUS_IN_MIN           0x02 
     260#define PC87365_STATUS_IN_MAX           0x04 
     261 
     262#define PC87365_SYSCTL_TEMP1            3101 /* degrees Celcius */ 
     263#define PC87365_SYSCTL_TEMP2            3102 
     264#define PC87365_SYSCTL_TEMP3            3103 /* not for PC87365 */ 
     265#define PC87365_SYSCTL_TEMP1_STATUS     3101 /* bit field */ 
     266#define PC87365_SYSCTL_TEMP2_STATUS     3102 
     267#define PC87365_SYSCTL_TEMP3_STATUS     3103 /* not for PC87365 */ 
     268 
     269#define PC87365_STATUS_TEMP_MIN         0x02 
     270#define PC87365_STATUS_TEMP_MAX         0x04 
     271#define PC87365_STATUS_TEMP_CRIT        0x08 
     272#define PC87365_STATUS_TEMP_OPEN        0x40 
    177273 
    178274/* -- SENSORS SYSCTL END -- */ 
    179275 
    180 static ctl_table pc87360_dir_table_template[] = { /* PC87363 too */ 
    181         {PC87360_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, 
    182          &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, 
    183         {PC87360_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, 
    184          &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, 
    185         {PC87360_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, 
    186          &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_div}, 
    187         {PC87360_SYSCTL_FAN1_STATUS, "fan1_status", NULL, 0, 0444, NULL, 
    188          &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, 
    189         {PC87360_SYSCTL_FAN2_STATUS, "fan2_status", NULL, 0, 0444, NULL, 
    190          &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, 
    191         {PC87360_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, 
    192          &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, 
    193         {PC87360_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, 
    194          &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, 
    195         {0} 
    196 }; 
    197  
    198 static ctl_table pc87364_dir_table_template[] = { /* PC87365 and PC87366 too */ 
     276static ctl_table pc87360_dir_table_template[] = { /* PC87363 and PC87364 too */ 
    199277        {PC87360_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, 
    200278         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, 
     
    220298}; 
    221299 
     300static ctl_table pc87365_dir_table_template[] = { /* PC87366 too */ 
     301        {PC87365_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, 
     302         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_alarms}, 
     303        {PC87360_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, 
     304         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, 
     305        {PC87360_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, 
     306         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, 
     307        {PC87360_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, 
     308         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, 
     309        {PC87360_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, 
     310         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_div}, 
     311        {PC87360_SYSCTL_FAN1_STATUS, "fan1_status", NULL, 0, 0444, NULL, 
     312         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, 
     313        {PC87360_SYSCTL_FAN2_STATUS, "fan2_status", NULL, 0, 0444, NULL, 
     314         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, 
     315        {PC87360_SYSCTL_FAN3_STATUS, "fan3_status", NULL, 0, 0444, NULL, 
     316         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, 
     317        {PC87360_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, 
     318         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, 
     319        {PC87360_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, 
     320         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, 
     321        {PC87360_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, 
     322         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, 
     323        {PC87365_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, 
     324         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, 
     325        {PC87365_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, 
     326         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, 
     327        {PC87365_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, 
     328         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, 
     329        {PC87365_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, 
     330         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, 
     331        {PC87365_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, 
     332         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, 
     333        {PC87365_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, 
     334         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, 
     335        {PC87365_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, 
     336         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, 
     337        {PC87365_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, 
     338         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, 
     339        {PC87365_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, 
     340         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, 
     341        {PC87365_SYSCTL_IN9, "in9", NULL, 0, 0644, NULL, 
     342         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, 
     343        {PC87365_SYSCTL_IN10, "in10", NULL, 0, 0644, NULL, 
     344         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, 
     345        {PC87365_SYSCTL_IN0_STATUS, "in0_status", NULL, 0, 0444, NULL, 
     346         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, 
     347        {PC87365_SYSCTL_IN1_STATUS, "in1_status", NULL, 0, 0444, NULL, 
     348         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, 
     349        {PC87365_SYSCTL_IN2_STATUS, "in2_status", NULL, 0, 0444, NULL, 
     350         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, 
     351        {PC87365_SYSCTL_IN3_STATUS, "in3_status", NULL, 0, 0444, NULL, 
     352         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, 
     353        {PC87365_SYSCTL_IN4_STATUS, "in4_status", NULL, 0, 0444, NULL, 
     354         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, 
     355        {PC87365_SYSCTL_IN5_STATUS, "in5_status", NULL, 0, 0444, NULL, 
     356         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, 
     357        {PC87365_SYSCTL_IN6_STATUS, "in6_status", NULL, 0, 0444, NULL, 
     358         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, 
     359        {PC87365_SYSCTL_IN7_STATUS, "in7_status", NULL, 0, 0444, NULL, 
     360         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, 
     361        {PC87365_SYSCTL_IN8_STATUS, "in8_status", NULL, 0, 0444, NULL, 
     362         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, 
     363        {PC87365_SYSCTL_IN9_STATUS, "in9_status", NULL, 0, 0444, NULL, 
     364         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, 
     365        {PC87365_SYSCTL_IN10_STATUS, "in10_status", NULL, 0, 0444, NULL, 
     366         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, 
     367        {PC87365_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, 
     368         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp}, 
     369        {PC87365_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, 
     370         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp}, 
     371        {PC87365_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, 
     372         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp}, 
     373        {PC87365_SYSCTL_TEMP1_STATUS, "temp1_status", NULL, 0, 0644, NULL, 
     374         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp_status}, 
     375        {PC87365_SYSCTL_TEMP2_STATUS, "temp2_status", NULL, 0, 0644, NULL, 
     376         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp_status}, 
     377        {PC87365_SYSCTL_TEMP3_STATUS, "temp3_status", NULL, 0, 0644, NULL, 
     378         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp_status}, 
     379        {0} 
     380}; 
     381 
    222382static int pc87360_attach_adapter(struct i2c_adapter *adapter) 
    223383{ 
     
    225385} 
    226386 
    227 static int pc87360_find(int *address, u8 *devid
     387static int pc87360_find(u8 *devid, int *address
    228388{ 
    229389        u16 val; 
     390        int i; 
     391        int nrdev; /* logical device count */ 
    230392 
    231393        /* no superio_enter */ 
     394 
     395        /* identify device */ 
    232396        val = superio_inb(DEVID); 
    233         if (!PC87360_DEVID_MATCH(val)) { 
     397        switch (val) { 
     398        case 0xE1: /* PC87360 */ 
     399        case 0xE8: /* PC87363 */ 
     400        case 0xE4: /* PC87364 */ 
     401                nrdev = 1; 
     402                break; 
     403        case 0xE5: /* PC87365 */ 
     404        case 0xE9: /* PC87366 */ 
     405                nrdev = 3; 
     406                break; 
     407        default: 
    234408                superio_exit(); 
    235409                return -ENODEV; 
    236410        } 
     411        /* remember the device id */ 
    237412        *devid = val; 
    238413 
    239         superio_select(); 
    240  
    241         val = superio_inb(PC87360_ACTIVATE_REG); 
    242         if (!(val & 0x01)) { 
    243                 printk("pc87360.o: device not activated\n"); 
    244                 superio_exit(); 
    245                 return -ENODEV; 
    246         } 
    247  
    248         val = (superio_inb(PC87360_BASE_REG) << 8) 
    249             | superio_inb(PC87360_BASE_REG + 1); 
    250         *address = val & ~(PC87360_EXTENT - 1); 
    251         if (*address == 0) { 
    252                 printk("pc87360.o: base address not set\n"); 
    253                 superio_exit(); 
    254                 return -ENODEV; 
     414        for (i = 0; i < nrdev; i++) { 
     415                /* select logical device */ 
     416                superio_outb(DEV, logdev[i]); 
     417 
     418                val = superio_inb(ACT); 
     419                if (!(val & 0x01)) { 
     420                        printk(KERN_INFO "pc87360.o: device 0x%02x not " 
     421                               "activated\n", logdev[i]); 
     422                        continue; 
     423                } 
     424 
     425                val = (superio_inb(BASE) << 8) 
     426                    | superio_inb(BASE + 1); 
     427                if (!val) { 
     428                        printk(KERN_INFO "pc87360.o: base address not set for " 
     429                               "device 0x%02x\n", logdev[i]); 
     430                        continue; 
     431                } 
     432 
     433                address[i] = val; 
    255434        } 
    256435 
     
    259438} 
    260439 
     440/* We should not trust the address, it is unset. 
     441   Read from extra_isa instead. */ 
    261442int pc87360_detect(struct i2c_adapter *adapter, int address, 
    262443                   unsigned short flags, int kind) 
     
    273454        } 
    274455 
    275         if (check_region(address, PC87360_EXTENT)) { 
    276                 printk("pc87360.o: region 0x%x already in use!\n", address); 
    277                 return -ENODEV; 
     456        for (i = 0; i < 3; i++) { 
     457                if (extra_isa[i] && check_region(extra_isa[i], PC87360_EXTENT)) { 
     458                        printk("pc87360.o: region 0x%x already in use!\n", address); 
     459                        return -ENODEV; 
     460                } 
    278461        } 
    279462 
     
    291474 
    292475        data->fannr = 2; 
    293  
     476        data->innr = 0; 
     477        data->tempnr = 0; 
     478         
    294479        switch (devid) { 
    295                 case 0xe8: 
    296                         type_name = "pc87363"; 
    297                         break; 
    298                 case 0xe4: 
    299                         type_name = "pc87364"; 
    300                         data->fannr = 3; 
    301                         break; 
    302                 case 0xe5: 
    303                         type_name = "pc87365"; 
    304                         data->fannr = 3; 
    305                         break; 
    306                 case 0xe9: 
    307                         type_name = "pc87366"; 
    308                         data->fannr = 3; 
    309                         break; 
    310         } 
    311  
    312         request_region(address, PC87360_EXTENT, "pc87360"); 
     480        case 0xe8: 
     481                type_name = "pc87363"; 
     482                break; 
     483        case 0xe4: 
     484                type_name = "pc87364"; 
     485                data->fannr = 3; 
     486                break; 
     487        case 0xe5: 
     488                type_name = "pc87365"; 
     489                data->fannr = 3; 
     490                data->innr = 11; 
     491                data->tempnr = 2; 
     492                break; 
     493        case 0xe9: 
     494                type_name = "pc87366"; 
     495                data->fannr = 3; 
     496                data->innr = 11; 
     497                data->tempnr = 3; 
     498                break; 
     499        } 
     500 
     501        for (i = 0; i < 3; i++) { 
     502                if ((data->address[i] = extra_isa[i])) { 
     503                        request_region(extra_isa[i], PC87360_EXTENT, "pc87360"); 
     504                } 
     505        } 
    313506        strcpy(new_client->name, client_name); 
    314507 
     
    321514 
    322515        if ((i = i2c_register_entry((struct i2c_client *) new_client, 
    323                                     type_name, 
    324                                     (data->fannr == 3) ? 
    325                                     pc87364_dir_table_template : 
     516                                    type_name, data->innr ? 
     517                                    pc87365_dir_table_template : 
    326518                                    pc87360_dir_table_template)) < 0) { 
    327519                err = i; 
     
    330522        data->sysctl_id = i; 
    331523 
    332         pc87360_init_client(new_client); 
    333524        return 0; 
    334525 
     
    343534static int pc87360_detach_client(struct i2c_client *client) 
    344535{ 
    345         int err; 
    346  
    347         i2c_deregister_entry(((struct pc87360_data *) (client->data))->sysctl_id); 
     536        struct pc87360_data *data = client->data; 
     537        int i, err; 
     538 
     539        i2c_deregister_entry(data->sysctl_id); 
    348540 
    349541        if ((err = i2c_detach_client(client))) { 
     
    353545        } 
    354546 
    355         release_region(client->addr, PC87360_EXTENT); 
     547        for (i = 0; i < 3; i++) { 
     548                if (data->address[i]) { 
     549                        release_region(data->address[i], PC87360_EXTENT); 
     550                } 
     551        } 
    356552        kfree(client->data); 
    357553 
     
    359555} 
    360556 
    361 static int pc87360_read_value(struct i2c_client *client, u8 reg) 
     557/* ldi is the logical device index: 
     558   0: fans 
     559   1: voltages 
     560   2: temperatures */ 
     561static int pc87360_read_value(struct pc87360_data *data, int ldi, u8 reg) 
    362562{ 
    363563        int res; 
    364564 
    365         res = inb_p(client->addr + reg); 
     565        down(&(data->lock)); 
     566        res = inb_p(data->address[ldi] + reg); 
     567        up(&(data->lock)); 
    366568        return res; 
    367569} 
    368570 
    369 static int pc87360_write_value(struct i2c_client *client, u8 reg, u8 value) 
    370 
    371         outb_p(value, client->addr + reg); 
     571static int pc87360_write_value(struct pc87360_data *data, int ldi, u8 reg, 
     572                               u8 value) 
     573
     574        down(&(data->lock)); 
     575        outb_p(value, data->address[ldi] + reg); 
     576        up(&(data->lock)); 
    372577        return 0; 
    373 } 
    374  
    375 static void pc87360_init_client(struct i2c_client *client) 
    376 { 
    377         /* nothing yet, read only driver */ 
    378578} 
    379579 
     
    388588            (jiffies < data->last_updated) || !data->valid) { 
    389589                for (i = 0; i < data->fannr; i++) { 
    390                         data->fan[i] = pc87360_read_value(client, PC87360_REG_FAN(i)); 
    391                         data->fan_min[i] = pc87360_read_value(client, PC87360_REG_FAN_MIN(i)); 
    392                         data->fan_status[i] = pc87360_read_value(client, PC87360_REG_FAN_STATUS(i)); 
    393                         data->pwm[i] = pc87360_read_value(client, PC87360_REG_PWM(i)); 
     590                        data->fan[i] = pc87360_read_value(data, 0, PC87360_REG_FAN(i)); 
     591                        data->fan_min[i] = pc87360_read_value(data, 0, PC87360_REG_FAN_MIN(i)); 
     592                        data->fan_status[i] = pc87360_read_value(data, 0, PC87360_REG_FAN_STATUS(i)); 
     593                        data->pwm[i] = pc87360_read_value(data, 0, PC87360_REG_PWM(i)); 
     594                } 
     595 
     596                for (i = 0; i < data->innr; i++) { 
     597                        pc87360_write_value(data, 1, PC87365_REG_IN_BANK, i); 
     598                        data->in_status[i] = pc87360_read_value(data, 1, PC87365_REG_IN_STATUS); 
     599                        if (data->in_status[i] & 0x01) { 
     600                                data->in[i] = pc87360_read_value(data, 1, PC87365_REG_IN); 
     601                                data->in_min[i] = pc87360_read_value(data, 1, PC87365_REG_IN_MIN); 
     602                                data->in_max[i] = pc87360_read_value(data, 1, PC87365_REG_IN_MAX); 
     603                        } 
     604                        data->in_alarms = pc87360_read_value(data, 1, PC87365_REG_IN_ALARMS1) 
     605                                        | (pc87360_read_value(data, 1, PC87365_REG_IN_ALARMS2) << 8); 
     606                } 
     607 
     608                for (i = 0; i < data->tempnr; i++) { 
     609                        pc87360_write_value(data, 2, PC87365_REG_TEMP_BANK, i); 
     610                        data->temp_status[i] = pc87360_read_value(data, 2, PC87365_REG_TEMP_STATUS); 
     611                        if (data->temp_status[i] & 0x01) { 
     612                                data->temp[i] = pc87360_read_value(data, 2, PC87365_REG_TEMP); 
     613                                data->temp_min[i] = pc87360_read_value(data, 2, PC87365_REG_TEMP_MIN); 
     614                                data->temp_max[i] = pc87360_read_value(data, 2, PC87365_REG_TEMP_MAX); 
     615                                data->temp_crit[i] = pc87360_read_value(data, 2, PC87365_REG_TEMP_CRIT); 
     616                        } 
     617                        data->temp_alarms = pc87360_read_value(data, 2, PC87365_REG_TEMP_ALARMS); 
    394618                } 
    395619 
     
    401625} 
    402626 
     627 
     628void pc87365_alarms(struct i2c_client *client, int operation, int ctl_name, 
     629                    int *nrels_mag, long *results) 
     630{ 
     631        struct pc87360_data *data = client->data; 
     632 
     633        if (operation == SENSORS_PROC_REAL_INFO) 
     634                *nrels_mag = 0; 
     635        else if (operation == SENSORS_PROC_REAL_READ) { 
     636                pc87360_update_client(client); 
     637                results[0] = data->in_alarms; 
     638                results[1] = data->temp_alarms; 
     639                *nrels_mag = 2; 
     640        } 
     641} 
    403642 
    404643void pc87360_fan(struct i2c_client *client, int operation, int ctl_name, 
     
    423662                        data->fan_min[nr] = FAN_TO_REG(results[0], 
    424663                                                       FAN_DIV_FROM_REG(data->fan_status[nr])); 
    425                         pc87360_write_value(client, PC87360_REG_FAN_MIN(nr), 
     664                        pc87360_write_value(data, 0, PC87360_REG_FAN_MIN(nr), 
    426665                                            data->fan_min[nr]); 
    427666                } 
     
    452691                        data->fan_status[i] = (data->fan_status[i] & 0x9F) 
    453692                                            | FAN_DIV_TO_REG(results[i]); 
    454                         pc87360_write_value(client, PC87360_REG_FAN_STATUS(i), 
     693                        pc87360_write_value(data, 0, PC87360_REG_FAN_STATUS(i), 
    455694                                            data->fan_status[i]); 
    456695                        data->fan_min[i] = FAN_TO_REG(fan_min, 
    457696                                                      FAN_DIV_FROM_REG(data->fan_status[i])); 
    458                         pc87360_write_value(client, PC87360_REG_FAN_MIN(i), 
     697                        pc87360_write_value(data, 0, PC87360_REG_FAN_MIN(i), 
    459698                                            data->fan_min[i]); 
    460699                } 
     
    479718                { 
    480719                        data->pwm[nr] = SENSORS_LIMIT(results[0], 0, 255); 
    481                         pc87360_write_value(client, PC87360_REG_PWM(nr), 
     720                        pc87360_write_value(data, 0, PC87360_REG_PWM(nr), 
    482721                                            data->pwm[nr]); 
    483722                } 
     
    495734        else if (operation == SENSORS_PROC_REAL_READ) { 
    496735                pc87360_update_client(client); 
    497                 results[0] = ALARM_FROM_REG(data->pwm[nr]); 
     736                results[0] = FAN_STATUS_FROM_REG(data->fan_status[nr]); 
    498737                *nrels_mag = 1; 
    499738        } 
    500739} 
    501740 
     741void pc87365_in(struct i2c_client *client, int operation, int ctl_name, 
     742                int *nrels_mag, long *results) 
     743{ 
     744        struct pc87360_data *data = client->data; 
     745        int nr = ctl_name - PC87365_SYSCTL_IN0; 
     746 
     747        if (operation == SENSORS_PROC_REAL_INFO) 
     748                *nrels_mag = 3; 
     749        else if (operation == SENSORS_PROC_REAL_READ) { 
     750                pc87360_update_client(client); 
     751                results[0] = IN_FROM_REG(data->in_max[nr]); 
     752                results[1] = IN_FROM_REG(data->in_min[nr]); 
     753                results[2] = IN_FROM_REG(data->in[nr]); 
     754                *nrels_mag = 3; 
     755        } 
     756} 
     757 
     758void pc87365_in_status(struct i2c_client *client, int operation, int ctl_name, 
     759                       int *nrels_mag, long *results) 
     760{ 
     761        struct pc87360_data *data = client->data; 
     762        int nr = ctl_name - PC87365_SYSCTL_IN0_STATUS; 
     763 
     764        if (operation == SENSORS_PROC_REAL_INFO) 
     765                *nrels_mag = 0; 
     766        else if (operation == SENSORS_PROC_REAL_READ) { 
     767                pc87360_update_client(client); 
     768                results[0] = IN_STATUS_FROM_REG(data->in_status[nr]); 
     769                *nrels_mag = 1; 
     770        } 
     771} 
     772 
     773void pc87365_temp(struct i2c_client *client, int operation, int ctl_name, 
     774                  int *nrels_mag, long *results) 
     775{ 
     776        struct pc87360_data *data = client->data; 
     777        int nr = ctl_name - PC87365_SYSCTL_TEMP1; 
     778 
     779        if (operation == SENSORS_PROC_REAL_INFO) 
     780                *nrels_mag = 0; 
     781        else if (operation == SENSORS_PROC_REAL_READ) { 
     782                pc87360_update_client(client); 
     783                results[0] = TEMP_FROM_REG(data->temp_max[nr]); 
     784                results[1] = TEMP_FROM_REG(data->temp_min[nr]); 
     785                results[1] = TEMP_FROM_REG(data->temp_crit[nr]); 
     786                results[2] = TEMP_FROM_REG(data->temp[nr]); 
     787                *nrels_mag = 4; 
     788        } 
     789} 
     790 
     791void pc87365_temp_status(struct i2c_client *client, int operation, int ctl_name, 
     792                         int *nrels_mag, long *results) 
     793{ 
     794        struct pc87360_data *data = client->data; 
     795        int nr = ctl_name - PC87365_SYSCTL_TEMP1_STATUS; 
     796 
     797        if (operation == SENSORS_PROC_REAL_INFO) 
     798                *nrels_mag = 0; 
     799        else if (operation == SENSORS_PROC_REAL_READ) { 
     800                pc87360_update_client(client); 
     801                results[0] = TEMP_STATUS_FROM_REG(data->temp_status[nr]); 
     802                *nrels_mag = 1; 
     803        } 
     804} 
     805 
     806 
    502807static int __init pc87360_init(void) 
    503808{ 
    504         int addr; 
    505  
    506809        printk("pc87360.o version %s (%s)\n", LM_VERSION, LM_DATE); 
    507810 
    508         if (pc87360_find(&addr, &devid)) { 
     811        if (pc87360_find(&devid, extra_isa)) { 
    509812                printk("pc87360.o: PC8736x not detected, module not inserted.\n"); 
    510813                return -ENODEV; 
    511814        } 
    512         normal_isa[0] = addr; 
    513815 
    514816        return i2c_add_driver(&pc87360_driver); 
  • lm-sensors/trunk/lib/chips.c

    r2427 r2453  
    42584258    { SENSORS_PC87360_FAN2, "fan2", NOMAP, NOMAP, R, 
    42594259                PC87360_SYSCTL_FAN2, VALUE(2), 0 }, 
     4260    { SENSORS_PC87360_FAN3, "fan3", NOMAP, NOMAP, R, 
     4261                PC87360_SYSCTL_FAN3, VALUE(2), 0 }, 
    42604262    { SENSORS_PC87360_FAN1_MIN, "fan1_min", SENSORS_PC87360_FAN1, 
    42614263                SENSORS_PC87360_FAN1, RW, PC87360_SYSCTL_FAN1, 
     
    42644266                SENSORS_PC87360_FAN2, RW, PC87360_SYSCTL_FAN2, 
    42654267                VALUE(1), 0 }, 
     4268    { SENSORS_PC87360_FAN3_MIN, "fan3_min", SENSORS_PC87360_FAN3, 
     4269                SENSORS_PC87360_FAN3, RW, PC87360_SYSCTL_FAN3, 
     4270                VALUE(1), 0 }, 
    42664271    { SENSORS_PC87360_FAN1_DIV, "fan1_div", SENSORS_PC87360_FAN1, 
    42674272                NOMAP, RW, PC87360_SYSCTL_FAN_DIV, VALUE(1), 0 }, 
    42684273    { SENSORS_PC87360_FAN2_DIV, "fan2_div", SENSORS_PC87360_FAN2, 
    42694274                NOMAP, RW, PC87360_SYSCTL_FAN_DIV, VALUE(2), 0 }, 
     4275    { SENSORS_PC87360_FAN3_DIV, "fan3_div", SENSORS_PC87360_FAN3, 
     4276                NOMAP, RW, PC87360_SYSCTL_FAN_DIV, VALUE(3), 0 }, 
    42704277    { SENSORS_PC87360_FAN1_STATUS, "fan1_status", SENSORS_PC87360_FAN1, 
    42714278                NOMAP, R, PC87360_SYSCTL_FAN1_STATUS, VALUE(1), 0 }, 
    42724279    { SENSORS_PC87360_FAN2_STATUS, "fan2_status", SENSORS_PC87360_FAN2, 
    42734280                NOMAP, R, PC87360_SYSCTL_FAN2_STATUS, VALUE(1), 0 }, 
     4281    { SENSORS_PC87360_FAN3_STATUS, "fan3_status", SENSORS_PC87360_FAN3, 
     4282                NOMAP, R, PC87360_SYSCTL_FAN3_STATUS, VALUE(1), 0 }, 
    42744283    { 0 } 
    42754284  }; 
    42764285 
    4277 static sensors_chip_feature pc87364_features[] = 
     4286static sensors_chip_feature pc87365_features[] = 
    42784287  {  
     4288    { SENSORS_PC87360_ALARMS_IN, "alarms_in", NOMAP, NOMAP, R, 
     4289                PC87365_SYSCTL_ALARMS, VALUE(1), 0 }, 
     4290    { SENSORS_PC87360_ALARMS_TEMP, "alarms_temp", NOMAP, NOMAP, R, 
     4291                PC87365_SYSCTL_ALARMS, VALUE(2), 0 }, 
    42794292    { SENSORS_PC87360_FAN1, "fan1", NOMAP, NOMAP, R, 
    42804293                PC87360_SYSCTL_FAN1, VALUE(2), 0 }, 
     
    43044317    { SENSORS_PC87360_FAN3_STATUS, "fan3_status", SENSORS_PC87360_FAN3, 
    43054318                NOMAP, R, PC87360_SYSCTL_FAN3_STATUS, VALUE(1), 0 }, 
     4319    { SENSORS_PC87360_IN0, "in0", NOMAP, NOMAP, R, 
     4320                PC87365_SYSCTL_IN0, VALUE(3), 2 }, 
     4321    { SENSORS_PC87360_IN1, "in1", NOMAP, NOMAP, R, 
     4322                PC87365_SYSCTL_IN1, VALUE(3), 2 }, 
     4323    { SENSORS_PC87360_IN2, "in2", NOMAP, NOMAP, R, 
     4324                PC87365_SYSCTL_IN2, VALUE(3), 2 }, 
     4325    { SENSORS_PC87360_IN3, "in3", NOMAP, NOMAP, R, 
     4326                PC87365_SYSCTL_IN3, VALUE(3), 2 }, 
     4327    { SENSORS_PC87360_IN4, "in4", NOMAP, NOMAP, R, 
     4328                PC87365_SYSCTL_IN4, VALUE(3), 2 }, 
     4329    { SENSORS_PC87360_IN5, "in5", NOMAP, NOMAP, R, 
     4330                PC87365_SYSCTL_IN5, VALUE(3), 2 }, 
     4331    { SENSORS_PC87360_IN6, "in6", NOMAP, NOMAP, R, 
     4332                PC87365_SYSCTL_IN6, VALUE(3), 2 }, 
     4333    { SENSORS_PC87360_IN7, "in7", NOMAP, NOMAP, R, 
     4334                PC87365_SYSCTL_IN7, VALUE(3), 2 }, 
     4335    { SENSORS_PC87360_IN8, "in8", NOMAP, NOMAP, R, 
     4336                PC87365_SYSCTL_IN8, VALUE(3), 2 }, 
     4337    { SENSORS_PC87360_IN9, "in9", NOMAP, NOMAP, R, 
     4338                PC87365_SYSCTL_IN9, VALUE(3), 2 }, 
     4339    { SENSORS_PC87360_IN10, "in10", NOMAP, NOMAP, R, 
     4340                PC87365_SYSCTL_IN10, VALUE(3), 2 }, 
     4341    { SENSORS_PC87360_IN0_MIN, "in0_min", SENSORS_PC87360_IN0, 
     4342                SENSORS_PC87360_IN0, RW, PC87365_SYSCTL_IN0, 
     4343                VALUE(1), 2 }, 
     4344    { SENSORS_PC87360_IN1_MIN, "in1_min", SENSORS_PC87360_IN1, 
     4345                SENSORS_PC87360_IN1, RW, PC87365_SYSCTL_IN1, 
     4346                VALUE(1), 2 }, 
     4347    { SENSORS_PC87360_IN2_MIN, "in2_min", SENSORS_PC87360_IN2, 
     4348                SENSORS_PC87360_IN2, RW, PC87365_SYSCTL_IN2, 
     4349                VALUE(1), 2 }, 
     4350    { SENSORS_PC87360_IN3_MIN, "in3_min", SENSORS_PC87360_IN3, 
     4351                SENSORS_PC87360_IN3, RW, PC87365_SYSCTL_IN3, 
     4352                VALUE(1), 2 }, 
     4353    { SENSORS_PC87360_IN4_MIN, "in4_min", SENSORS_PC87360_IN4, 
     4354                SENSORS_PC87360_IN4, RW, PC87365_SYSCTL_IN4, 
     4355                VALUE(1), 2 }, 
     4356    { SENSORS_PC87360_IN5_MIN, "in5_min", SENSORS_PC87360_IN5, 
     4357                SENSORS_PC87360_IN5, RW, PC87365_SYSCTL_IN5, 
     4358                VALUE(1), 2 }, 
     4359    { SENSORS_PC87360_IN6_MIN, "in6_min", SENSORS_PC87360_IN6, 
     4360                SENSORS_PC87360_IN6, RW, PC87365_SYSCTL_IN6, 
     4361                VALUE(1), 2 }, 
     4362    { SENSORS_PC87360_IN7_MIN, "in7_min", SENSORS_PC87360_IN7, 
     4363                SENSORS_PC87360_IN7, RW, PC87365_SYSCTL_IN7, 
     4364                VALUE(1), 2 }, 
     4365    { SENSORS_PC87360_IN8_MIN, "in8_min", SENSORS_PC87360_IN8, 
     4366                SENSORS_PC87360_IN8, RW, PC87365_SYSCTL_IN8, 
     4367                VALUE(1), 2 }, 
     4368    { SENSORS_PC87360_IN9_MIN, "in9_min", SENSORS_PC87360_IN9, 
     4369                SENSORS_PC87360_IN9, RW, PC87365_SYSCTL_IN9,