root/lm-sensors/trunk/kernel/chips/pc87360.c @ 2784

Revision 2784, 41.2 KB (checked in by khali, 8 years ago)

Restore controlling_mod argument to i2c_register_entry(). This
is needed to properly lock chip drivers in memory while anyone uses their
/proc entries. This also brings back compatibility with the 2.4 Linux
kernel.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 *  pc87360.c - Part of lm_sensors, Linux kernel modules
3 *              for hardware monitoring
4 *  Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
5 *
6 *  Copied from smsc47m1.c:
7 *  Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
8 *
9 *  This program is free software; you can redistribute it and/or modify
10 *  it under the terms of the GNU General Public License as published by
11 *  the Free Software Foundation; either version 2 of the License, or
12 *  (at your option) any later version.
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 *  Supports the following chips:
24 *
25 *  Chip        #vin    #fan    #pwm    #temp   devid
26 *  PC87360     -       2       2       -       0xE1
27 *  PC87363     -       2       2       -       0xE8
28 *  PC87364     -       3       3       -       0xE4
29 *  PC87365     11      3       3       2       0xE5
30 *  PC87366     11      3       3       3-4     0xE9
31 *
32 *  This driver assumes that no more than one chip is present, and the
33 *  standard Super-I/O address is used (0x2E/0x2F).
34 */
35
36#include <linux/module.h>
37#include <linux/slab.h>
38#include <linux/ioport.h>
39#include <linux/i2c.h>
40#include <linux/i2c-proc.h>
41#include <linux/init.h>
42#include <asm/io.h>
43#include "version.h"
44#include "sensors_vid.h"
45
46static unsigned short normal_i2c[] = { SENSORS_I2C_END };
47static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
48static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END };
49static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
50static struct i2c_force_data forces[] = {{NULL}};
51static u8 devid;
52static unsigned int extra_isa[] = { 0x0000, 0x0000, 0x0000 };
53static u8 confreg[4];
54
55enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 };
56static struct i2c_address_data addr_data = {
57        .normal_i2c             = normal_i2c,
58        .normal_i2c_range       = normal_i2c_range,
59        .normal_isa             = normal_isa,
60        .normal_isa_range       = normal_isa_range,
61        .probe                  = normal_i2c,           /* cheat */
62        .probe_range            = normal_i2c_range,     /* cheat */
63        .ignore                 = normal_i2c,           /* cheat */
64        .ignore_range           = normal_i2c_range,     /* cheat */
65        .forces                 = forces,
66};
67
68static int init = 1;
69MODULE_PARM(init, "i");
70MODULE_PARM_DESC(init,
71        "Chip initialization level:\n"
72        " 0: None\n"
73        "*1: Forcibly enable internal voltage and temperature channels, except in9\n"
74        " 2: Forcibly enable all voltage and temperature channels, except in9\n"
75        " 3: Forcibly enable all voltage and temperature channels, including in9");
76
77/*
78 * Super-I/O registers and operations
79 */
80
81#define DEV     0x07    /* Register: Logical device select */
82#define DEVID   0x20    /* Register: Device ID */
83#define ACT     0x30    /* Register: Device activation */
84#define BASE    0x60    /* Register: Base address */
85
86#define FSCM    0x09    /* Logical device: fans */
87#define VLM     0x0d    /* Logical device: voltages */
88#define TMS     0x0e    /* Logical device: temperatures */
89static const u8 logdev[3] = { FSCM, VLM, TMS };
90
91#define LD_FAN          0
92#define LD_IN           1
93#define LD_TEMP         2
94
95static inline void superio_outb(int sioaddr, int reg, int val)
96{
97        outb(reg, sioaddr);
98        outb(val, sioaddr+1);
99}
100
101static inline int superio_inb(int sioaddr, int reg)
102{
103        outb(reg, sioaddr);
104        return inb(sioaddr+1);
105}
106
107static inline void superio_exit(int sioaddr)
108{
109        outb(0x02, sioaddr);
110        outb(0x02, sioaddr+1);
111}
112
113/*
114 * Logical devices
115 */
116
117#define PC87360_EXTENT          0x10
118#define PC87365_REG_BANK        0x09
119#define NO_BANK                 0xff
120
121/*
122 * Fan registers and conversions
123 */
124
125/* nr has to be 0 or 1 (PC87360/87363) or 2 (PC87364/87365/87366) */
126#define PC87360_REG_PRESCALE(nr)        (0x00 + 2 * (nr))
127#define PC87360_REG_PWM(nr)             (0x01 + 2 * (nr))
128#define PC87360_REG_FAN_MIN(nr)         (0x06 + 3 * (nr))
129#define PC87360_REG_FAN(nr)             (0x07 + 3 * (nr))
130#define PC87360_REG_FAN_STATUS(nr)      (0x08 + 3 * (nr))
131
132#define FAN_FROM_REG(val,div)           ((val)==0?0: \
133                                         480000/((val)*(div)))
134#define FAN_TO_REG(val,div)             ((val)<=100?0: \
135                                         480000/((val)*(div)))
136#define FAN_DIV_FROM_REG(val)           (1 << ((val >> 5) & 0x03))
137#define FAN_DIV_TO_REG(val)             ((val)==8?0x60:(val)==4?0x40: \
138                                         (val)==1?0x00:0x20)
139#define FAN_STATUS_FROM_REG(val)        ((val) & 0x07)
140
141#define FAN_CONFIG_MONITOR(val,nr)      (((val) >> (2 + nr * 3)) & 1)
142#define FAN_CONFIG_CONTROL(val,nr)      (((val) >> (3 + nr * 3)) & 1)
143#define FAN_CONFIG_INVERT(val,nr)       (((val) >> (4 + nr * 3)) & 1)
144
145#define PWM_FROM_REG(val,inv)           ((inv) ? 255 - (val) : (val))
146static inline u8 PWM_TO_REG(int val, int inv)
147{
148        if (inv)
149                val = 255 - val;
150        if (val < 0)
151                return 0;
152        if (val > 255)
153                return 255;
154        return val;
155}
156
157/*
158 * Voltage registers and conversions
159 */
160
161#define PC87365_REG_IN_CONVRATE         0x07
162#define PC87365_REG_IN_CONFIG           0x08
163#define PC87365_REG_IN                  0x0B
164#define PC87365_REG_IN_MIN              0x0D
165#define PC87365_REG_IN_MAX              0x0C
166#define PC87365_REG_IN_STATUS           0x0A
167#define PC87365_REG_IN_ALARMS1          0x00
168#define PC87365_REG_IN_ALARMS2          0x01
169#define PC87365_REG_VID                 0x06
170
171#define IN_FROM_REG(val,ref)            (((val) * (ref) + 128) / 256)
172#define IN_TO_REG(val,ref)              ((val)<0 ? 0 : \
173                                         (val)*256>=(ref)*255 ? 255: \
174                                         ((val) * 256 + (ref) / 2) / (ref))
175
176/*
177 * Temperature registers and conversions
178 */
179
180#define PC87365_REG_TEMP_CONFIG         0x08
181#define PC87365_REG_TEMP                0x0B
182#define PC87365_REG_TEMP_MIN            0x0D
183#define PC87365_REG_TEMP_MAX            0x0C
184#define PC87365_REG_TEMP_CRIT           0x0E
185#define PC87365_REG_TEMP_STATUS         0x0A
186#define PC87365_REG_TEMP_ALARMS         0x00
187
188#define TEMP_FROM_REG(val)              ((val)&0x80 ? (val) - 0x100 : (val))
189#define TEMP_TO_REG(val)                ((val)<-55 ? 201 : (val)>127 ? 0x7F : \
190                                         (val)<0 ? (val) + 0x100 : (val))
191
192struct pc87360_data {
193        struct i2c_client client;
194        struct semaphore lock;
195        int sysctl_id;
196        int address[3];
197
198        struct semaphore update_lock;
199        char valid;             /* !=0 if following fields are valid */
200        unsigned long last_updated;     /* In jiffies */
201
202        u8 fannr, innr, tempnr;
203
204        u8 fan[3];              /* Register value */
205        u8 fan_min[3];          /* Register value */
206        u8 fan_status[3];       /* Register value */
207        u8 pwm[3];              /* Register value */
208        u16 fan_conf;           /* Configuration register values, combined */
209
210        u16 in_vref;            /* 10mV/bit */
211        u8 in[14];              /* Register value */
212        u8 in_min[14];          /* Register value */
213        u8 in_max[14];          /* Register value */
214        u8 in_crit[3];          /* Register value */
215        u8 in_status[14];       /* Register value */
216        u16 in_alarms;          /* Register values, combined, masked */
217        u8 vid_conf;            /* Configuration register value */
218        u8 vrm;
219        u8 vid;                 /* Register value */
220
221        u8 temp[3];             /* Register value */
222        u8 temp_min[3];         /* Register value */
223        u8 temp_max[3];         /* Register value */
224        u8 temp_crit[3];        /* Register value */
225        u8 temp_status[3];      /* Register value */
226        u8 temp_alarms;         /* Register value, masked */
227};
228
229
230static int pc87360_attach_adapter(struct i2c_adapter *adapter);
231static int pc87360_detect(struct i2c_adapter *adapter, int address,
232                          unsigned short flags, int kind);
233static int pc87360_detach_client(struct i2c_client *client);
234
235static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
236                              u8 reg);
237static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
238                                u8 reg, u8 value);
239static void pc87360_init_client(struct i2c_client *client, int use_thermistors);
240static void pc87360_update_client(struct i2c_client *client);
241
242
243void pc87365_alarms(struct i2c_client *client, int operation, int ctl_name,
244                    int *nrels_mag, long *results);
245
246static void pc87360_fan(struct i2c_client *client, int operation,
247                        int ctl_name, int *nrels_mag, long *results);
248static void pc87360_fan_status(struct i2c_client *client, int operation,
249                               int ctl_name, int *nrels_mag, long *results);
250static void pc87360_fan_div(struct i2c_client *client, int operation,
251                            int ctl_name, int *nrels_mag, long *results);
252static void pc87360_pwm(struct i2c_client *client, int operation,
253                        int ctl_name, int *nrels_mag, long *results);
254
255void pc87365_in(struct i2c_client *client, int operation, int ctl_name,
256                int *nrels_mag, long *results);
257void pc87365_in_status(struct i2c_client *client, int operation, int ctl_name,
258                       int *nrels_mag, long *results);
259void pc87365_vid(struct i2c_client *client, int operation, int ctl_name,
260                 int *nrels_mag, long *results);
261void pc87365_vrm(struct i2c_client *client, int operation, int ctl_name,
262                 int *nrels_mag, long *results);
263
264void pc87365_temp(struct i2c_client *client, int operation, int ctl_name,
265                  int *nrels_mag, long *results);
266void pc87365_temp_status(struct i2c_client *client, int operation, int ctl_name,
267                         int *nrels_mag, long *results);
268
269static int pc87360_id = 0;
270
271static struct i2c_driver pc87360_driver = {
272        .name           = "PC8736x hardware monitor",
273        .flags          = I2C_DF_NOTIFY,
274        .attach_adapter = pc87360_attach_adapter,
275        .detach_client  = pc87360_detach_client,
276};
277
278/* -- SENSORS SYSCTL START -- */
279
280#define PC87365_SYSCTL_ALARMS           100 /* bit field */
281
282#define PC87360_SYSCTL_FAN1             1101 /* Rotations/min */
283#define PC87360_SYSCTL_FAN2             1102
284#define PC87360_SYSCTL_FAN3             1103 /* not for PC87360/PC87363 */
285#define PC87360_SYSCTL_FAN_DIV          1201 /* 1, 2, 4 or 8 */
286#define PC87360_SYSCTL_FAN1_STATUS      1301 /* bit field */
287#define PC87360_SYSCTL_FAN2_STATUS      1302
288#define PC87360_SYSCTL_FAN3_STATUS      1303 /* not for PC87360/PC87363 */
289#define PC87360_SYSCTL_PWM1             1401 /* 0-255 */
290#define PC87360_SYSCTL_PWM2             1402
291#define PC87360_SYSCTL_PWM3             1403 /* not for PC87360/PC87363 */
292
293#define PC87360_STATUS_FAN_READY        0x01
294#define PC87360_STATUS_FAN_LOW          0x02
295#define PC87360_STATUS_FAN_OVERFLOW     0x04
296
297#define PC87365_SYSCTL_IN0              2100 /* mV */
298#define PC87365_SYSCTL_IN1              2101
299#define PC87365_SYSCTL_IN2              2102
300#define PC87365_SYSCTL_IN3              2103
301#define PC87365_SYSCTL_IN4              2104
302#define PC87365_SYSCTL_IN5              2105
303#define PC87365_SYSCTL_IN6              2106
304#define PC87365_SYSCTL_IN7              2107
305#define PC87365_SYSCTL_IN8              2108
306#define PC87365_SYSCTL_IN9              2109
307#define PC87365_SYSCTL_IN10             2110
308#define PC87365_SYSCTL_TEMP4            2111 /* not for PC87365 */
309#define PC87365_SYSCTL_TEMP5            2112 /* not for PC87365 */
310#define PC87365_SYSCTL_TEMP6            2113 /* not for PC87365 */
311#define PC87365_SYSCTL_IN0_STATUS       2300 /* bit field */
312#define PC87365_SYSCTL_IN1_STATUS       2301
313#define PC87365_SYSCTL_IN2_STATUS       2302
314#define PC87365_SYSCTL_IN3_STATUS       2303
315#define PC87365_SYSCTL_IN4_STATUS       2304
316#define PC87365_SYSCTL_IN5_STATUS       2305
317#define PC87365_SYSCTL_IN6_STATUS       2306
318#define PC87365_SYSCTL_IN7_STATUS       2307
319#define PC87365_SYSCTL_IN8_STATUS       2308
320#define PC87365_SYSCTL_IN9_STATUS       2309
321#define PC87365_SYSCTL_IN10_STATUS      2310
322#define PC87365_SYSCTL_TEMP4_STATUS     2311 /* not for PC87365 */
323#define PC87365_SYSCTL_TEMP5_STATUS     2312 /* not for PC87365 */
324#define PC87365_SYSCTL_TEMP6_STATUS     2313 /* not for PC87365 */
325
326#define PC87365_SYSCTL_VID              2400
327#define PC87365_SYSCTL_VRM              2401
328
329#define PC87365_STATUS_IN_MIN           0x02
330#define PC87365_STATUS_IN_MAX           0x04
331
332#define PC87365_SYSCTL_TEMP1            3101 /* degrees Celcius */
333#define PC87365_SYSCTL_TEMP2            3102
334#define PC87365_SYSCTL_TEMP3            3103 /* not for PC87365 */
335#define PC87365_SYSCTL_TEMP1_STATUS     3301 /* bit field */
336#define PC87365_SYSCTL_TEMP2_STATUS     3302
337#define PC87365_SYSCTL_TEMP3_STATUS     3303 /* not for PC87365 */
338
339#define PC87365_STATUS_TEMP_MIN         0x02
340#define PC87365_STATUS_TEMP_MAX         0x04
341#define PC87365_STATUS_TEMP_CRIT        0x08
342#define PC87365_STATUS_TEMP_OPEN        0x40
343
344/* -- SENSORS SYSCTL END -- */
345
346static ctl_table pc87360_dir_table_template[] = { /* PC87363 and PC87364 too */
347        {PC87360_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL,
348         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan},
349        {PC87360_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL,
350         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan},
351        {PC87360_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL,
352         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan},
353        {PC87360_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL,
354         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_div},
355        {PC87360_SYSCTL_FAN1_STATUS, "fan1_status", NULL, 0, 0444, NULL,
356         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status},
357        {PC87360_SYSCTL_FAN2_STATUS, "fan2_status", NULL, 0, 0444, NULL,
358         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status},
359        {PC87360_SYSCTL_FAN3_STATUS, "fan3_status", NULL, 0, 0444, NULL,
360         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status},
361        {PC87360_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL,
362         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm},
363        {PC87360_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL,
364         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm},
365        {PC87360_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL,
366         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm},
367        {0}
368};
369
370static ctl_table pc87365_dir_table_template[] = { /* PC87366 too */
371        {PC87365_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL,
372         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_alarms},
373        {PC87360_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL,
374         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan},
375        {PC87360_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL,
376         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan},
377        {PC87360_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL,
378         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan},
379        {PC87360_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL,
380         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_div},
381        {PC87360_SYSCTL_FAN1_STATUS, "fan1_status", NULL, 0, 0444, NULL,
382         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status},
383        {PC87360_SYSCTL_FAN2_STATUS, "fan2_status", NULL, 0, 0444, NULL,
384         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status},
385        {PC87360_SYSCTL_FAN3_STATUS, "fan3_status", NULL, 0, 0444, NULL,
386         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status},
387        {PC87360_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL,
388         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm},
389        {PC87360_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL,
390         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm},
391        {PC87360_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL,
392         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm},
393        {PC87365_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL,
394         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
395        {PC87365_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL,
396         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
397        {PC87365_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL,
398         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
399        {PC87365_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL,
400         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
401        {PC87365_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL,
402         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
403        {PC87365_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL,
404         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
405        {PC87365_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL,
406         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
407        {PC87365_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL,
408         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
409        {PC87365_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL,
410         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
411        {PC87365_SYSCTL_IN9, "in9", NULL, 0, 0644, NULL,
412         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
413        {PC87365_SYSCTL_IN10, "in10", NULL, 0, 0644, NULL,
414         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
415        {PC87365_SYSCTL_IN0_STATUS, "in0_status", NULL, 0, 0444, NULL,
416         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
417        {PC87365_SYSCTL_IN1_STATUS, "in1_status", NULL, 0, 0444, NULL,
418         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
419        {PC87365_SYSCTL_IN2_STATUS, "in2_status", NULL, 0, 0444, NULL,
420         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
421        {PC87365_SYSCTL_IN3_STATUS, "in3_status", NULL, 0, 0444, NULL,
422         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
423        {PC87365_SYSCTL_IN4_STATUS, "in4_status", NULL, 0, 0444, NULL,
424         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
425        {PC87365_SYSCTL_IN5_STATUS, "in5_status", NULL, 0, 0444, NULL,
426         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
427        {PC87365_SYSCTL_IN6_STATUS, "in6_status", NULL, 0, 0444, NULL,
428         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
429        {PC87365_SYSCTL_IN7_STATUS, "in7_status", NULL, 0, 0444, NULL,
430         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
431        {PC87365_SYSCTL_IN8_STATUS, "in8_status", NULL, 0, 0444, NULL,
432         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
433        {PC87365_SYSCTL_IN9_STATUS, "in9_status", NULL, 0, 0444, NULL,
434         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
435        {PC87365_SYSCTL_IN10_STATUS, "in10_status", NULL, 0, 0444, NULL,
436         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
437        {PC87365_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL,
438         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp},
439        {PC87365_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL,
440         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp},
441        {PC87365_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL,
442         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp},
443        {PC87365_SYSCTL_TEMP4, "temp4", NULL, 0, 0644, NULL,
444         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
445        {PC87365_SYSCTL_TEMP5, "temp5", NULL, 0, 0644, NULL,
446         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
447        {PC87365_SYSCTL_TEMP6, "temp6", NULL, 0, 0644, NULL,
448         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
449        {PC87365_SYSCTL_TEMP1_STATUS, "temp1_status", NULL, 0, 0444, NULL,
450         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp_status},
451        {PC87365_SYSCTL_TEMP2_STATUS, "temp2_status", NULL, 0, 0444, NULL,
452         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp_status},
453        {PC87365_SYSCTL_TEMP3_STATUS, "temp3_status", NULL, 0, 0444, NULL,
454         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp_status},
455        {PC87365_SYSCTL_TEMP4_STATUS, "temp4_status", NULL, 0, 0444, NULL,
456         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
457        {PC87365_SYSCTL_TEMP5_STATUS, "temp5_status", NULL, 0, 0444, NULL,
458         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
459        {PC87365_SYSCTL_TEMP6_STATUS, "temp6_status", NULL, 0, 0444, NULL,
460         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
461        {PC87365_SYSCTL_VID, "vid", NULL, 0, 0444, NULL,
462         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_vid},
463        {PC87365_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL,
464         &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_vrm},
465        {0}
466};
467
468static int pc87360_attach_adapter(struct i2c_adapter *adapter)
469{
470        return i2c_detect(adapter, &addr_data, pc87360_detect);
471}
472
473static int pc87360_find(int sioaddr, u8 *devid, int *address)
474{
475        u16 val;
476        int i;
477        int nrdev; /* logical device count */
478
479        /* No superio_enter */
480
481        /* Identify device */
482        val = superio_inb(sioaddr, DEVID);
483        switch (val) {
484        case 0xE1: /* PC87360 */
485        case 0xE8: /* PC87363 */
486        case 0xE4: /* PC87364 */
487                nrdev = 1;
488                break;
489        case 0xE5: /* PC87365 */
490        case 0xE9: /* PC87366 */
491                nrdev = 3;
492                break;
493        default:
494                superio_exit(sioaddr);
495                return -ENODEV;
496        }
497        /* Remember the device id */
498        *devid = val;
499
500        for (i = 0; i < nrdev; i++) {
501                /* select logical device */
502                superio_outb(sioaddr, DEV, logdev[i]);
503
504                val = superio_inb(sioaddr, ACT);
505                if (!(val & 0x01)) {
506                        printk(KERN_INFO "pc87360.o: Device 0x%02x not "
507                               "activated\n", logdev[i]);
508                        continue;
509                }
510
511                val = (superio_inb(sioaddr, BASE) << 8)
512                    | superio_inb(sioaddr, BASE + 1);
513                if (!val) {
514                        printk(KERN_INFO "pc87360.o: Base address not set for "
515                               "device 0x%02x\n", logdev[i]);
516                        continue;
517                }
518
519                address[i] = val;
520
521                if (i==0) { /* Fans */
522                        confreg[0] = superio_inb(sioaddr, 0xF0);
523                        confreg[1] = superio_inb(sioaddr, 0xF1);
524                       
525#ifdef DEBUG
526                        printk(KERN_DEBUG "pc87360.o: Fan 1: mon=%d "
527                               "ctrl=%d inv=%d\n", (confreg[0]>>2)&1,
528                               (confreg[0]>>3)&1, (confreg[0]>>4)&1);
529                        printk(KERN_DEBUG "pc87360.o: Fan 2: mon=%d "
530                               "ctrl=%d inv=%d\n", (confreg[0]>>5)&1,
531                               (confreg[0]>>6)&1, (confreg[0]>>7)&1);
532                        printk(KERN_DEBUG "pc87360.o: Fan 3: mon=%d "
533                               "ctrl=%d inv=%d\n", confreg[1]&1,
534                               (confreg[1]>>1)&1, (confreg[1]>>2)&1);
535#endif
536                } else if (i==1) { /* Voltages */
537                        /* Are we using thermistors? */
538                        if (*devid == 0xE9) { /* PC87366 */
539                                /* These registers are not logical-device
540                                   specific, just that we won't need them if
541                                   we don't use the VLM device */
542                                confreg[2] = superio_inb(sioaddr, 0x2B);
543                                confreg[3] = superio_inb(sioaddr, 0x25);
544
545                                if (confreg[2] & 0x40) {
546                                        printk(KERN_INFO "pc87360.o: Using "
547                                               "thermistors for temperature "
548                                               "monitoring\n");
549                                }
550                                if (confreg[3] & 0xE0) {
551                                        printk(KERN_INFO "pc87360.o: VID "
552                                               "inputs routed (mode %u)\n",
553                                                confreg[3] >> 5);
554                                }
555                        }
556                }
557        }
558
559        superio_exit(sioaddr);
560        return 0;
561}
562
563/* We don't really care about the address.
564   Read from extra_isa instead. */
565int pc87360_detect(struct i2c_adapter *adapter, int address,
566                   unsigned short flags, int kind)
567{
568        int i;
569        struct i2c_client *new_client;
570        struct pc87360_data *data;
571        int err = 0;
572        const char *type_name = "pc87360";
573        const char *client_name = "PC8736x chip";
574        ctl_table *template = pc87360_dir_table_template;
575        int use_thermistors = 0;
576
577        if (!i2c_is_isa_adapter(adapter)) {
578                return 0;
579        }
580
581        for (i = 0; i < 3; i++) {
582                if (extra_isa[i]
583                 && check_region(extra_isa[i], PC87360_EXTENT)) {
584                        printk(KERN_ERR "pc87360.o: Region 0x%x-0x%x already "
585                               "in use!\n", extra_isa[i],
586                               extra_isa[i]+PC87360_EXTENT-1);
587                        return -ENODEV;
588                }
589        }
590
591        if (!(data = kmalloc(sizeof(struct pc87360_data), GFP_KERNEL))) {
592                return -ENOMEM;
593        }
594        memset(data, 0x00, sizeof(struct pc87360_data));
595
596        new_client = &data->client;
597        new_client->addr = address;
598        init_MUTEX(&data->lock);
599        new_client->data = data;
600        new_client->adapter = adapter;
601        new_client->driver = &pc87360_driver;
602        new_client->flags = 0;
603
604        data->fannr = 2;
605        data->innr = 0;
606        data->tempnr = 0;
607       
608        switch (devid) {
609        case 0xe8:
610                type_name = "pc87363";
611                break;
612        case 0xe4:
613                type_name = "pc87364";
614                data->fannr = 3;
615                break;
616        case 0xe5:
617                type_name = "pc87365";
618                template = pc87365_dir_table_template;
619                data->fannr = extra_isa[0] ? 3 : 0;
620                data->innr = extra_isa[1] ? 11 : 0;
621                data->tempnr = extra_isa[2] ? 2 : 0;
622                break;
623        case 0xe9:
624                type_name = "pc87366";
625                template = pc87365_dir_table_template;
626                data->fannr = extra_isa[0] ? 3 : 0;
627                data->innr = extra_isa[1] ? 14 : 0;
628                data->tempnr = extra_isa[2] ? 3 : 0;
629                break;
630        }
631
632        /* Retrieve the fans configuration from Super-I/O space */
633        if (data->fannr)
634                data->fan_conf = confreg[0] | (confreg[1] << 8);
635
636        for (i = 0; i < 3; i++) {
637                if ((data->address[i] = extra_isa[i])) {
638                        request_region(extra_isa[i], PC87360_EXTENT, "pc87360");
639                }
640        }
641        strcpy(new_client->name, client_name);
642
643        new_client->id = pc87360_id++;
644        data->valid = 0;
645        init_MUTEX(&data->update_lock);
646
647        if ((err = i2c_attach_client(new_client)))
648                goto ERROR1;
649
650        /* Use the correct reference voltage
651           Unless both the VLM and the TMS logical devices agree to
652           use an external Vref, the internal one is used. */
653        if (data->innr) {
654                i = pc87360_read_value(data, LD_IN, NO_BANK,
655                                       PC87365_REG_IN_CONFIG);
656                if (data->tempnr) {
657                        i &= pc87360_read_value(data, LD_TEMP, NO_BANK,
658                                                PC87365_REG_TEMP_CONFIG);
659                }
660                data->in_vref = (i&0x02) ? 3025 : 2966;
661#ifdef DEBUG
662                printk(KERN_DEBUG "pc87360.o: Using %s reference voltage\n",
663                       (i&0x02) ? "external" : "internal");
664#endif
665
666                data->vid_conf = confreg[3];
667                data->vrm = 90;
668        }
669
670        /* Fan clock dividers may be needed before any data is read */
671        for (i = 0; i < data->fannr; i++) {
672                data->fan_status[i] = pc87360_read_value(data, LD_FAN,
673                                      NO_BANK, PC87360_REG_FAN_STATUS(i));
674        }
675
676        if (init > 0) {
677                if (devid == 0xe9 && data->address[1]) /* PC87366 */
678                        use_thermistors = confreg[2] & 0x40;
679
680                pc87360_init_client(new_client, use_thermistors);
681        }
682
683        if ((i = i2c_register_entry((struct i2c_client *) new_client,
684                                    type_name, template, THIS_MODULE)) < 0) {
685                err = i;
686                goto ERROR2;
687        }
688        data->sysctl_id = i;
689
690        return 0;
691
692ERROR2:
693        i2c_detach_client(new_client);
694ERROR1:
695        for (i = 0; i < 3; i++) {
696                if (data->address[i]) {
697                        release_region(data->address[i], PC87360_EXTENT);
698                }
699        }
700        kfree(data);
701        return err;
702}
703
704static int pc87360_detach_client(struct i2c_client *client)
705{
706        struct pc87360_data *data = client->data;
707        int i, err;
708
709        i2c_deregister_entry(data->sysctl_id);
710
711        if ((err = i2c_detach_client(client))) {
712                printk(KERN_ERR "pc87360.o: Client deregistration failed, "
713                       "client not detached.\n");
714                return err;
715        }
716
717        for (i = 0; i < 3; i++) {
718                if (data->address[i]) {
719                        release_region(data->address[i], PC87360_EXTENT);
720                }
721        }
722        kfree(client->data);
723
724        return 0;
725}
726
727/* ldi is the logical device index
728   bank is for voltages and temperatures only */
729static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
730                              u8 reg)
731{
732        int res;
733
734        down(&(data->lock));
735        if (bank != NO_BANK) {
736                outb_p(bank, data->address[ldi] + PC87365_REG_BANK);
737        }
738        res = inb_p(data->address[ldi] + reg);
739        up(&(data->lock));
740        return res;
741}
742
743static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
744                                u8 reg, u8 value)
745{
746        down(&(data->lock));
747        if (bank != NO_BANK) {
748                outb_p(bank, data->address[ldi] + PC87365_REG_BANK);
749        }
750        outb_p(value, data->address[ldi] + reg);
751        up(&(data->lock));
752}
753
754static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
755{
756        struct pc87360_data *data = client->data;
757        int i, nr;
758        const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 };
759        const u8 init_temp[3] = { 2, 2, 1 };
760        u8 reg;
761
762        if (init >= 2 && data->innr) {
763                reg = pc87360_read_value(data, LD_IN, NO_BANK,
764                                         PC87365_REG_IN_CONVRATE);
765                printk(KERN_INFO "pc87360.o: VLM conversion set to"
766                       "1s period, 160us delay\n");
767                pc87360_write_value(data, LD_IN, NO_BANK,
768                                    PC87365_REG_IN_CONVRATE,
769                                    (reg & 0xC0) | 0x11);
770        }
771
772        nr = data->innr < 11 ? data->innr : 11;
773        for (i=0; i<nr; i++) {
774                if (init >= init_in[i]) {
775                        /* Forcibly enable voltage channel */
776                        reg = pc87360_read_value(data, LD_IN, i,
777                                                 PC87365_REG_IN_STATUS);
778                        if (!(reg & 0x01)) {
779#ifdef DEBUG
780                                printk(KERN_DEBUG "pc87360.o: Forcibly "
781                                       "enabling in%d\n", i);
782#endif
783                                pc87360_write_value(data, LD_IN, i,
784                                                    PC87365_REG_IN_STATUS,
785                                                    (reg & 0x68) | 0x87);
786                        }
787                }
788        }
789
790        /* We can't blindly trust the Super-I/O space configuration bit,
791           most BIOS won't set it properly */
792        for (i=11; i<data->innr; i++) {
793                reg = pc87360_read_value(data, LD_IN, i,
794                                         PC87365_REG_TEMP_STATUS);
795                use_thermistors = use_thermistors || (reg & 0x01);
796        }
797
798        i = use_thermistors ? 2 : 0;
799        for (; i<data->tempnr; i++) {
800                if (init >= init_temp[i]) {
801                        /* Forcibly enable temperature channel */
802                        reg = pc87360_read_value(data, LD_TEMP, i,
803                                                 PC87365_REG_TEMP_STATUS);
804                        if (!(reg & 0x01)) {
805#ifdef DEBUG
806                                printk(KERN_DEBUG "pc87360.o: Forcibly "
807                                       "enabling temp%d\n", i+1);
808#endif
809                                pc87360_write_value(data, LD_TEMP, i,
810                                                    PC87365_REG_TEMP_STATUS,
811                                                    0xCF);
812                        }
813                }
814        }
815
816        if (use_thermistors) {
817                for (i=11; i<data->innr; i++) {
818                        if (init >= init_in[i]) {
819                                /* The pin may already be used by thermal
820                                   diodes */
821                                reg = pc87360_read_value(data, LD_TEMP, (i-11)/2,
822                                                         PC87365_REG_TEMP_STATUS);
823                                if (reg & 0x01) {
824#ifdef DEBUG
825                                        printk(KERN_DEBUG "pc87360.o: Skipping "
826                                               "temp%d, pin already in use by "
827                                               "temp%d\n", i-7, (i-11)/2);
828#endif
829                                        continue;
830                                }
831                       
832                                /* Forcibly enable thermistor channel */
833                                reg = pc87360_read_value(data, LD_IN, i,
834                                                         PC87365_REG_IN_STATUS);
835                                if (!(reg & 0x01)) {
836#ifdef DEBUG
837                                        printk(KERN_DEBUG "pc87360.o: Forcibly "
838                                               "enabling temp%d\n", i-7);
839#endif
840                                        pc87360_write_value(data, LD_IN, i,
841                                                            PC87365_REG_TEMP_STATUS,
842                                                            (reg & 0x60) | 0x8F);
843                                }
844                        }
845                }
846        }
847
848        if (data->innr) {
849                reg = pc87360_read_value(data, LD_IN, NO_BANK,
850                                         PC87365_REG_IN_CONFIG);
851                if (reg & 0x01) {
852#ifdef DEBUG
853                        printk(KERN_DEBUG "pc87360.o: Forcibly "
854                               "enabling monitoring (VLM)\n");
855#endif
856                        pc87360_write_value(data, LD_IN, NO_BANK,
857                                            PC87365_REG_IN_CONFIG,
858                                            reg & 0xFE);
859                }
860        }
861
862        if (data->tempnr) {
863                reg = pc87360_read_value(data, LD_TEMP, NO_BANK,
864                                         PC87365_REG_TEMP_CONFIG);
865                if (reg & 0x01) {
866#ifdef DEBUG
867                        printk(KERN_DEBUG "pc87360.o: Forcibly "
868                               "enabling monitoring (TMS)\n");
869#endif
870                        pc87360_write_value(data, LD_TEMP, NO_BANK,
871                                            PC87365_REG_TEMP_CONFIG,
872                                            reg & 0xFE);
873                }
874
875                if (init >= 2) {
876                        /* Chip config as documented by National Semi. */
877                        pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08);
878                        /* We voluntarily omit the bank here, in case the
879                           sequence itself matters. It shouldn't be a problem,
880                           since nobody else is supposed to access the
881                           device at that point. */
882                        pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04);
883                        pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35);
884                        pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05);
885                        pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05);
886                }
887        }
888}
889
890static void pc87360_autodiv(struct pc87360_data *data, int nr)
891{
892        u8 old_min = data->fan_min[nr];
893
894        /* Increase clock divider if needed and possible */
895        if ((data->fan_status[nr] & 0x04) /* overflow flag */
896         || (data->fan[nr] >= 224)) { /* next to overflow */
897                if ((data->fan_status[nr] & 0x60) != 0x60) {
898                        data->fan_status[nr] += 0x20;
899                        data->fan_min[nr] >>= 1;
900                        data->fan[nr] >>= 1;
901#ifdef DEBUG
902                        printk(KERN_DEBUG "pc87360.o: Increasing "
903                               "clock divider to %d for fan %d\n",
904                               FAN_DIV_FROM_REG(data->fan_status[nr]),
905                               nr+1);
906#endif
907                }
908        } else {
909                /* Decrease clock divider if possible */
910                while (!(data->fan_min[nr] & 0x80) /* fan min "nails" divider */
911                 && data->fan[nr] < 85 /* bad accuracy */
912                 && (data->fan_status[nr] & 0x60) != 0x00) {
913                        data->fan_status[nr] -= 0x20;
914                        data->fan_min[nr] <<= 1;
915                        data->fan[nr] <<= 1;
916#ifdef DEBUG
917                        printk(KERN_DEBUG "pc87360.o: Decreasing "
918                               "clock divider to %d for fan %d\n",
919                               FAN_DIV_FROM_REG(data->fan_status[nr]),
920                               nr+1);
921#endif
922                }
923        }
924
925        /* Write new fan min if it changed */
926        if (old_min != data->fan_min[nr]) {
927                pc87360_write_value(data, LD_FAN, NO_BANK,
928                                    PC87360_REG_FAN_MIN(nr),
929                                    data->fan_min[nr]);
930        }
931}
932
933static void pc87360_update_client(struct i2c_client *client)
934{
935        struct pc87360_data *data = client->data;
936        u8 i;
937
938        down(&data->update_lock);
939
940        if ((jiffies - data->last_updated > HZ * 2) ||
941            (jiffies < data->last_updated) || !data->valid) {
942#ifdef DEBUG
943                printk(KERN_DEBUG "pc87360.o: Data update\n");
944#endif
945
946                /* Fans */
947                for (i = 0; i < data->fannr; i++) {
948                        if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {
949                                data->fan_status[i] = pc87360_read_value(data,
950                                                      LD_FAN, NO_BANK,
951                                                      PC87360_REG_FAN_STATUS(i));
952                                data->fan[i] = pc87360_read_value(data, LD_FAN,
953                                               NO_BANK, PC87360_REG_FAN(i));
954                                data->fan_min[i] = pc87360_read_value(data,
955                                                   LD_FAN, NO_BANK,
956                                                   PC87360_REG_FAN_MIN(i));
957                                /* Change clock divider if needed */
958                                pc87360_autodiv(data, i);
959                                /* Clear bits and write new divider */
960                                pc87360_write_value(data, LD_FAN, NO_BANK,
961                                                    PC87360_REG_FAN_STATUS(i),
962                                                    data->fan_status[i]);
963                        }
964                        data->pwm[i] = pc87360_read_value(data, LD_FAN,
965                                       NO_BANK, PC87360_REG_PWM(i));
966                }
967
968                /* Voltages */
969                for (i = 0; i < data->innr; i++) {
970                        data->in_status[i] = pc87360_read_value(data, LD_IN, i,
971                                             PC87365_REG_IN_STATUS);
972                        /* Clear bits */
973                        pc87360_write_value(data, LD_IN, i,
974                                            PC87365_REG_IN_STATUS,
975                                            data->in_status[i]);
976                        if ((data->in_status[i] & 0x81) == 0x81) {
977                                data->in[i] = pc87360_read_value(data, LD_IN,
978                                              i, PC87365_REG_IN);
979                        }
980                        if (data->in_status[i] & 0x01) {
981                                data->in_min[i] = pc87360_read_value(data,
982                                                  LD_IN, i,
983                                                  PC87365_REG_IN_MIN);
984                                data->in_max[i] = pc87360_read_value(data,
985                                                  LD_IN, i,
986                                                  PC87365_REG_IN_MAX);
987                                if (i >= 11)
988                                        data->in_crit[i-11] =
989                                                pc87360_read_value(data, LD_IN,
990                                                i, PC87365_REG_TEMP_CRIT);
991                        }
992                }
993                if (data->innr) {
994                        data->in_alarms = pc87360_read_value(data, LD_IN,
995                                          NO_BANK, PC87365_REG_IN_ALARMS1)
996                                        | ((pc87360_read_value(data, LD_IN,
997                                            NO_BANK, PC87365_REG_IN_ALARMS2)
998                                            & 0x07) << 8);
999                        data->vid = (data->vid_conf & 0xE0) ?
1000                                    pc87360_read_value(data, LD_IN,
1001                                    NO_BANK, PC87365_REG_VID) : 0x1F;
1002                }
1003
1004                /* Temperatures */
1005                for (i = 0; i < data->tempnr; i++) {
1006                        data->temp_status[i] = pc87360_read_value(data,
1007                                               LD_TEMP, i,
1008                                               PC87365_REG_TEMP_STATUS);
1009                        /* Clear bits */
1010                        pc87360_write_value(data, LD_TEMP, i,
1011                                            PC87365_REG_TEMP_STATUS,
1012                                            data->temp_status[i]);
1013                        if ((data->temp_status[i] & 0x81) == 0x81) {
1014                                data->temp[i] = pc87360_read_value(data,
1015                                                LD_TEMP, i,
1016                                                PC87365_REG_TEMP);
1017                        }
1018                        if (data->temp_status[i] & 0x01) {
1019                                data->temp_min[i] = pc87360_read_value(data,
1020                                                    LD_TEMP, i,
1021                                                    PC87365_REG_TEMP_MIN);
1022                                data->temp_max[i] = pc87360_read_value(data,
1023                                                    LD_TEMP, i,
1024                                                    PC87365_REG_TEMP_MAX);
1025                                data->temp_crit[i] = pc87360_read_value(data,
1026                                                     LD_TEMP, i,
1027                                                     PC87365_REG_TEMP_CRIT);
1028                        }
1029                }
1030                if (data->tempnr) {
1031                        data->temp_alarms = pc87360_read_value(data, LD_TEMP,
1032                                            NO_BANK, PC87365_REG_TEMP_ALARMS)
1033                                          & 0x3F;
1034                }
1035
1036                data->last_updated = jiffies;
1037                data->valid = 1;
1038        }
1039
1040        up(&data->update_lock);
1041}
1042
1043
1044void pc87365_alarms(struct i2c_client *client, int operation, int ctl_name,
1045                    int *nrels_mag, long *results)
1046{
1047        struct pc87360_data *data = client->data;
1048
1049        if (operation == SENSORS_PROC_REAL_INFO)
1050                *nrels_mag = 0;
1051        else if (operation == SENSORS_PROC_REAL_READ) {
1052                pc87360_update_client(client);
1053                results[0] = data->in_alarms;
1054                results[1] = data->temp_alarms;
1055                *nrels_mag = 2;
1056        }
1057}
1058
1059void pc87360_fan(struct i2c_client *client, int operation, int ctl_name,
1060                 int *nrels_mag, long *results)
1061{
1062        struct pc87360_data *data = client->data;
1063        int nr = ctl_name - PC87360_SYSCTL_FAN1;
1064
1065        if (operation == SENSORS_PROC_REAL_INFO)
1066                *nrels_mag = 0;
1067        else if (operation == SENSORS_PROC_REAL_READ) {
1068                pc87360_update_client(client);
1069                results[0] = FAN_FROM_REG(data->fan_min[nr],
1070                             FAN_DIV_FROM_REG(data->fan_status[nr]));
1071                results[1] = FAN_FROM_REG(data->fan[nr],
1072                             FAN_DIV_FROM_REG(data->fan_status[nr]));
1073                *nrels_mag = 2;
1074        }
1075        /* We ignore National's recommendation */
1076        else if (operation == SENSORS_PROC_REAL_WRITE) {
1077                if (nr >= data->fannr)
1078                        return;
1079                if (*nrels_mag >= 1) {
1080                        int fan_min = FAN_TO_REG(results[0],
1081                                      FAN_DIV_FROM_REG(data->fan_status[nr]));
1082                        /* If it wouldn't fit, change clock divisor */
1083                        while (fan_min > 255
1084                            && (data->fan_status[nr] & 0x60) != 0x60) {
1085                                fan_min >>= 1;
1086                                data->fan[nr] >>= 1;
1087                                data->fan_status[nr] += 0x20;
1088                        }
1089                        data->fan_min[nr] = fan_min > 255 ? 255 : fan_min;
1090                        pc87360_write_value(data, LD_FAN, NO_BANK,
1091                                            PC87360_REG_FAN_MIN(nr),
1092                                            data->fan_min[nr]);
1093                        /* Write new divider, preserve alarm bits */
1094                        pc87360_write_value(data, LD_FAN, NO_BANK,
1095                                            PC87360_REG_FAN_STATUS(nr),
1096                                            data->fan_status[nr] & 0xF9);
1097                }
1098        }
1099}
1100
1101void pc87360_fan_div(struct i2c_client *client, int operation,
1102                     int ctl_name, int *nrels_mag, long *results)
1103{
1104        struct pc87360_data *data = client->data;
1105        int i;
1106
1107        if (operation == SENSORS_PROC_REAL_INFO)
1108                *nrels_mag = 0;
1109        else if (operation == SENSORS_PROC_REAL_READ) {
1110                pc87360_update_client(client);
1111                for (i = 0; i < data->fannr; i++) {
1112                        results[i] = FAN_DIV_FROM_REG(data->fan_status[i]);
1113                }
1114                for (; i < 3; i++) {
1115                        results[i] = 0;
1116                }
1117                *nrels_mag = 3;
1118        }
1119}
1120
1121void pc87360_pwm(struct i2c_client *client, int operation, int ctl_name,
1122                 int *nrels_mag, long *results)
1123{
1124        struct pc87360_data *data = client->data;
1125        int nr = ctl_name - PC87360_SYSCTL_PWM1;
1126
1127        if (operation == SENSORS_PROC_REAL_INFO)
1128                *nrels_mag = 0;
1129        else if (operation == SENSORS_PROC_REAL_READ) {
1130                pc87360_update_client(client);
1131                results[0] = PWM_FROM_REG(data->pwm[nr],
1132                             FAN_CONFIG_INVERT(data->fan_conf, nr));
1133                results[1] = FAN_CONFIG_CONTROL(data->fan_conf, nr);
1134                *nrels_mag = 2;
1135        }
1136        else if (operation == SENSORS_PROC_REAL_WRITE) {
1137                if (nr >= data->fannr)
1138                        return;
1139                if (*nrels_mag >= 1) {
1140                        data->pwm[nr] = PWM_TO_REG(results[0],
1141                                        FAN_CONFIG_INVERT(data->fan_conf, nr));
1142                        pc87360_write_value(data, LD_FAN, NO_BANK,
1143                                            PC87360_REG_PWM(nr),
1144                                            data->pwm[nr]);
1145                }
1146        }
1147}
1148
1149void pc87360_fan_status(struct i2c_client *client, int operation, int ctl_name,
1150                        int *nrels_mag, long *results)
1151{
1152        struct pc87360_data *data = client->data;
1153        int nr = ctl_name - PC87360_SYSCTL_FAN1_STATUS;
1154
1155        if (operation == SENSORS_PROC_REAL_INFO)
1156                *nrels_mag = 0;
1157        else if (operation == SENSORS_PROC_REAL_READ) {
1158                pc87360_update_client(client);
1159                results[0] = FAN_STATUS_FROM_REG(data->fan_status[nr]);
1160                *nrels_mag = 1;
1161        }
1162}
1163
1164void pc87365_in(struct i2c_client *client, int operation, int ctl_name,
1165                int *nrels_mag, long *results)
1166{
1167        struct pc87360_data *data = client->data;
1168        int nr = ctl_name - PC87365_SYSCTL_IN0;
1169
1170        if (operation == SENSORS_PROC_REAL_INFO)
1171                *nrels_mag = 3;
1172        else if (operation == SENSORS_PROC_REAL_READ) {
1173                pc87360_update_client(client);
1174                results[0] = IN_FROM_REG(data->in_min[nr], data->in_vref);
1175                results[1] = IN_FROM_REG(data->in_max[nr], data->in_vref);
1176                if (nr < 11) {
1177                        *nrels_mag = 3;
1178                } else {
1179                        results[2] = IN_FROM_REG(data->in_crit[nr-11],
1180                                                 data->in_vref);
1181                        *nrels_mag = 4;
1182                }
1183                results[(*nrels_mag)-1] = IN_FROM_REG(data->in[nr],
1184                                                      data->in_vref);
1185        }
1186        else if (operation == SENSORS_PROC_REAL_WRITE) {
1187                if (*nrels_mag >= 1) {
1188                        data->in_min[nr] = IN_TO_REG(results[0],
1189                                                     data->in_vref);
1190                        pc87360_write_value(data, LD_IN, nr,
1191                                            PC87365_REG_IN_MIN,
1192                                            data->in_min[nr]);
1193                }
1194                if (*nrels_mag >= 2) {
1195                        data->in_max[nr] = IN_TO_REG(results[1],
1196                                                     data->in_vref);
1197                        pc87360_write_value(data, LD_IN, nr,
1198                                            PC87365_REG_IN_MAX,
1199                                            data->in_max[nr]);
1200                }
1201                if (*nrels_mag >= 3 && nr >= 11) {
1202                        data->in_crit[nr-11] = IN_TO_REG(results[2],
1203                                                         data->in_vref);
1204                        pc87360_write_value(data, LD_IN, nr,
1205                                            PC87365_REG_TEMP_CRIT,
1206                                            data->in_crit[nr-11]);
1207                }
1208        }
1209}
1210
1211void pc87365_in_status(struct i2c_client *client, int operation, int ctl_name,
1212                       int *nrels_mag, long *results)
1213{
1214        struct pc87360_data *data = client->data;
1215        int nr = ctl_name - PC87365_SYSCTL_IN0_STATUS;
1216
1217        if (operation == SENSORS_PROC_REAL_INFO)
1218                *nrels_mag = 0;
1219        else if (operation == SENSORS_PROC_REAL_READ) {
1220                pc87360_update_client(client);
1221                results[0] = data->in_status[nr];
1222                *nrels_mag = 1;
1223        }
1224}
1225
1226void pc87365_vid(struct i2c_client *client, int operation, int ctl_name,
1227                 int *nrels_mag, long *results)
1228{
1229        struct pc87360_data *data = client->data;
1230        if (operation == SENSORS_PROC_REAL_INFO)
1231                *nrels_mag = 3;
1232        else if (operation == SENSORS_PROC_REAL_READ) {
1233                pc87360_update_client(client);
1234                results[0] = vid_from_reg(data->vid & 0x1f, data->vrm);
1235                *nrels_mag = 1;
1236        }
1237}
1238
1239void pc87365_vrm(struct i2c_client *client, int operation, int ctl_name,
1240                 int *nrels_mag, long *results)
1241{
1242        struct pc87360_data *data = client->data;
1243        if (operation == SENSORS_PROC_REAL_INFO)
1244                *nrels_mag = 1;
1245        else if (operation == SENSORS_PROC_REAL_READ) {
1246                results[0] = data->vrm;
1247                *nrels_mag = 1;
1248        } else if (operation == SENSORS_PROC_REAL_WRITE) {
1249                if (*nrels_mag >= 1)
1250                        data->vrm = results[0];
1251        }
1252}
1253
1254void pc87365_temp(struct i2c_client *client, int operation, int ctl_name,
1255                  int *nrels_mag, long *results)
1256{
1257        struct pc87360_data *data = client->data;
1258        int nr = ctl_name - PC87365_SYSCTL_TEMP1;
1259
1260        if (operation == SENSORS_PROC_REAL_INFO)
1261                *nrels_mag = 0;
1262        else if (operation == SENSORS_PROC_REAL_READ) {
1263                pc87360_update_client(client);
1264                results[0] = TEMP_FROM_REG(data->temp_max[nr]);
1265                results[1] = TEMP_FROM_REG(data->temp_min[nr]);
1266                results[2] = TEMP_FROM_REG(data->temp_crit[nr]);
1267                results[3] = TEMP_FROM_REG(data->temp[nr]);
1268                *nrels_mag = 4;
1269        }
1270        else if (operation == SENSORS_PROC_REAL_WRITE) {
1271                if (nr >= data->tempnr)
1272                        return;
1273                if (*nrels_mag >= 1) {
1274                        data->temp_max[nr] = TEMP_TO_REG(results[0]);
1275                        pc87360_write_value(data, LD_TEMP, nr,
1276                                            PC87365_REG_TEMP_MAX,
1277                                            data->temp_max[nr]);
1278                }
1279                if (*nrels_mag >= 2) {
1280                        data->temp_min[nr] = TEMP_TO_REG(results[1]);
1281                        pc87360_write_value(data, LD_TEMP, nr,
1282                                            PC87365_REG_TEMP_MIN,
1283                                            data->temp_min[nr]);
1284                }
1285                if (*nrels_mag >= 3) {
1286                        data->temp_crit[nr] = TEMP_TO_REG(results[2]);
1287                        pc87360_write_value(data, LD_TEMP, nr,
1288                                            PC87365_REG_TEMP_CRIT,
1289                                            data->temp_crit[nr]);
1290                }
1291        }
1292}
1293
1294void pc87365_temp_status(struct i2c_client *client, int operation, int ctl_name,
1295                         int *nrels_mag, long *results)
1296{
1297        struct pc87360_data *data = client->data;
1298        int nr = ctl_name - PC87365_SYSCTL_TEMP1_STATUS;
1299
1300        if (operation == SENSORS_PROC_REAL_INFO)
1301                *nrels_mag = 0;
1302        else if (operation == SENSORS_PROC_REAL_READ) {
1303                pc87360_update_client(client);
1304                results[0] = data->temp_status[nr];
1305                *nrels_mag = 1;
1306        }
1307}
1308
1309
1310static int __init pc87360_init(void)
1311{
1312        int i;
1313
1314        printk(KERN_INFO "pc87360.o version %s (%s)\n", LM_VERSION, LM_DATE);
1315
1316        if (pc87360_find(0x2e, &devid, extra_isa)
1317         && pc87360_find(0x4e, &devid, extra_isa)) {
1318                printk(KERN_WARNING "pc87360.o: PC8736x not detected, "
1319                       "module not inserted.\n");
1320                return -ENODEV;
1321        }
1322
1323        /* Arbitrarily pick one of the addresses */
1324        for (i = 0; i < 3; i++) {
1325                if (extra_isa[i] != 0x0000) {
1326                        normal_isa[0] = extra_isa[i];
1327                        break;
1328                }
1329        }
1330
1331        if (normal_isa[0] == 0x0000) {
1332                printk(KERN_WARNING "pc87360.o: No active logical device, "
1333                       "module not inserted.\n");
1334                return -ENODEV;
1335       
1336        }
1337
1338        return i2c_add_driver(&pc87360_driver);
1339}
1340
1341static void __exit pc87360_exit(void)
1342{
1343        i2c_del_driver(&pc87360_driver);
1344}
1345
1346
1347MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
1348MODULE_DESCRIPTION("PC8736x hardware monitor");
1349MODULE_LICENSE("GPL");
1350
1351module_init(pc87360_init);
1352module_exit(pc87360_exit);
Note: See TracBrowser for help on using the browser.