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

Revision 2713, 41.2 KB (checked in by khali, 10 years ago)

Support secondary Super-I/O address (0x4e/0x4f).

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