root/lm-sensors/trunk/kernel/chips/mtp008.c @ 2286

Revision 2286, 29.6 KB (checked in by khali, 9 years ago)

Do not include unneeded headers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2   mtp008.c - Part of lm_sensors, Linux kernel modules for hardware
3   monitoring
4   Copyright (c) 2001  Kris Van Hees <aedil@alchar.org>
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#include <linux/module.h>
22#include <linux/slab.h>
23#include <linux/i2c.h>
24#include <linux/i2c-proc.h>
25#include <linux/init.h>
26#include "version.h"
27
28MODULE_LICENSE("GPL");
29
30/* Addresses to scan */
31static unsigned short normal_i2c[] = {SENSORS_I2C_END};
32static unsigned short normal_i2c_range[] = {0x2c, 0x2e, SENSORS_I2C_END};
33static unsigned int normal_isa[] = {SENSORS_ISA_END};
34static unsigned int normal_isa_range[] = {SENSORS_ISA_END};
35
36/* Insmod parameters */
37SENSORS_INSMOD_1(mtp008);
38
39/* The MTP008 registers */
40/*      in0 .. in6 */
41#define MTP008_REG_IN(nr)               (0x20 + (nr))
42#define MTP008_REG_IN_MAX(nr)           (0x2b + (nr) * 2)
43#define MTP008_REG_IN_MIN(nr)           (0x2c + (nr) * 2)
44
45/*      temp1 */
46#define MTP008_REG_TEMP                 0x27
47#define MTP008_REG_TEMP_MAX             0x39
48#define MTP008_REG_TEMP_MIN             0x3a
49
50/*      fan1 .. fan3 */
51#define MTP008_REG_FAN(nr)              (0x27 + (nr))
52#define MTP008_REG_FAN_MIN(nr)          (0x3a + (nr))
53
54#define MTP008_REG_CONFIG               0x40
55#define MTP008_REG_INT_STAT1            0x41
56#define MTP008_REG_INT_STAT2            0x42
57
58#define MTP008_REG_SMI_MASK1            0x43
59#define MTP008_REG_SMI_MASK2            0x44
60
61#define MTP008_REG_NMI_MASK1            0x45
62#define MTP008_REG_NMI_MASK2            0x46
63
64#define MTP008_REG_VID_FANDIV           0x47
65
66#define MTP008_REG_I2C_ADDR             0x48
67
68#define MTP008_REG_RESET_VID4           0x49
69
70#define MTP008_REG_OVT_PROP             0x50
71
72#define MTP008_REG_BEEP_CTRL1           0x51
73#define MTP008_REG_BEEP_CTRL2           0x52
74
75/*      pwm1 .. pwm3  nr range 1-3 */
76#define MTP008_REG_PWM_CTRL(nr)         (0x52 + (nr))
77
78#define MTP008_REG_PIN_CTRL1            0x56
79#define MTP008_REG_PIN_CTRL2            0x57
80
81#define MTP008_REG_CHIPID               0x58
82
83/*
84 * Pin control register configuration constants.
85 */
86#define MTP008_CFG_VT1_PII              0x08
87#define MTP008_CFG_VT2_AIN              0x00
88#define MTP008_CFG_VT2_VT               0x03
89#define MTP008_CFG_VT2_PII              0x04
90#define MTP008_CFG_VT2_MASK             0x06
91#define MTP008_CFG_VT3_VT               0x01
92
93/* sensor pin types */
94#define VOLTAGE         1
95#define THERMISTOR      2
96#define PIIDIODE        3
97
98/*
99 * Conversion routines and macros.  Limit checking is only done on
100 * the TO_REG variants.
101 *
102 * Note that IN values are expressed as 100 times the actual voltage to avoid
103 * having to use floating point values.  As such, IN values are between 0 and
104 * 409 (0V to 4.096V).
105 */
106#define IN_TO_REG(val)          (SENSORS_LIMIT((((val) * 10 + 8) / 16), 0, 255))
107#define IN_FROM_REG(val)        (((val) * 16 + 5) / 10)
108
109/*
110 * The fan cotation count (as stored in the register) is calculated using the
111 * following formula:
112 *      count = (22.5K * 60) / (rpm * div) = 1350000 / (rpm * div)
113 * and the rpm is therefore:
114 *      rpm = 1350000 / (count * div)
115 */
116static inline u8 FAN_TO_REG(long rpm, int div)
117{
118        if (rpm == 0)
119                return 255;
120
121        rpm = SENSORS_LIMIT(rpm, 1, 1000000);
122
123        return SENSORS_LIMIT(
124                 (1350000 + rpm * div / 2) / (rpm * div),
125                 1, 254
126               );
127}
128
129#define FAN_FROM_REG(val, div)  ((val) == 0 ? -1                              \
130                                            : (val) == 255 ? 0                \
131                                                           : 1350000 /        \
132                                                             ((val) * (div))  \
133                                )
134
135/*
136 * Temperatures are stored as two's complement values of the Celsius value.  It
137 * actually uses 10 times the Celsius value to avoid using floating point
138 * values.
139 */
140#define TEMP_TO_REG(val)        (                                             \
141                                 (val) < 0                                    \
142                                    ? SENSORS_LIMIT(((val) - 5) / 10, 0, 255) \
143                                    : SENSORS_LIMIT(((val) + 5) / 10, 0, 255) \
144                                )
145#define TEMP_FROM_REG(val)      (                                             \
146                                 (                                            \
147                                  (val) > 0x80 ? (val) - 0x100                \
148                                               : (val)                        \
149                                 ) * 10                                       \
150                                )
151
152/*
153 * VCORE voltage:
154 *      0x00 to 0x0f    = 2.05 to 1.30 (0.05 per unit)
155 *      0x10 to 0x1e    = 3.50 to 2.10 (0.10 per unit)
156 *      0x1f            = No CPU
157 */
158#define VID_FROM_REG(val)       ((val) == 0x1f                                \
159                                         ? 0                                  \
160                                         : (val) < 0x10 ? 205 - (val) * 5     \
161                                                        : 510 - (val) * 10)
162
163/*
164 * Fan divider.
165 */
166#define DIV_FROM_REG(val)       (1 << (val))
167#define DIV_TO_REG(val)         ((val) == 8 ? 3                               \
168                                            : (val) == 4 ? 2                  \
169                                                         : (val) == 2 ? 1     \
170                                                                      : 0)
171
172/*
173 * Alarms (interrupt status).
174 */
175#define ALARMS_FROM_REG(val)    (val)
176
177/*
178 * Beep controls.
179 */
180#define BEEPS_FROM_REG(val)     (val)
181#define BEEPS_TO_REG(val)       (val)
182
183/*
184 * PWM control. nr range 1 to 3
185 */
186#define PWM_FROM_REG(val)       (val)
187#define PWM_TO_REG(val)         (val)
188#define PWMENABLE_FROM_REG(nr, val)     (((val) >> ((nr) + 3)) & 1)
189
190/*
191 * For each registered MTP008, we need to keep some data in memory.  The
192 * structure itself is dynamically allocated, at the same time when a new
193 * mtp008 client is allocated.
194 */
195struct mtp008_data {
196        int sysctl_id;
197        enum chips type;
198
199        struct semaphore update_lock;
200        char valid;                             /* !=0 if fields are valid */
201        unsigned long last_updated;             /* In jiffies */
202
203        u8 in[7];                               /* Register value */
204        u8 in_max[7];                           /* Register value */
205        u8 in_min[7];                           /* Register value */
206        u8 temp;                                /* Register value */
207        u8 temp_max;                            /* Register value */
208        u8 temp_min;                            /* Register value */
209        u8 fan[3];                              /* Register value */
210        u8 fan_min[3];                          /* Register value */
211        u8 vid;                                 /* Register encoding */
212        u8 fan_div[3];                          /* Register encoding */
213        u16 alarms;                             /* Register encoding */
214        u16 beeps;                              /* Register encoding */
215        u8 pwm[4];                              /* Register value */
216        u8 sens[3];                             /* 1 = Analog input,
217                                                   2 = Thermistor,
218                                                   3 = PII/Celeron diode */
219        u8 pwmenable;                           /* Register 0x57 value */
220};
221
222static int mtp008_attach_adapter(struct i2c_adapter *adapter);
223static int mtp008_detect(struct i2c_adapter *adapter, int address,
224                         unsigned short flags, int kind);
225static int mtp008_detach_client(struct i2c_client *client);
226
227static int mtp008_read_value(struct i2c_client *client, u8 register);
228static int mtp008_write_value(struct i2c_client *client, u8 register, u8 value);
229static void mtp008_update_client(struct i2c_client *client);
230static void mtp008_init_client(struct i2c_client *client);
231
232static void mtp008_in(struct i2c_client *client, int operation,
233                      int ctl_name, int *nrels_mag, long *results);
234static void mtp008_fan(struct i2c_client *client, int operation,
235                       int ctl_name, int *nrels_mag, long *results);
236static void mtp008_temp(struct i2c_client *client, int operation,
237                        int ctl_name, int *nrels_mag, long *results);
238static void mtp008_temp_add(struct i2c_client *client, int operation,
239                            int ctl_name, int *nrels_mag, long *results);
240static void mtp008_vid(struct i2c_client *client, int operation,
241                       int ctl_name, int *nrels_mag, long *results);
242static void mtp008_fan_div(struct i2c_client *client, int operation,
243                           int ctl_name, int *nrels_mag, long *results);
244static void mtp008_alarms(struct i2c_client *client, int operation,
245                          int ctl_name, int *nrels_mag, long *results);
246static void mtp008_beep(struct i2c_client *client, int operation,
247                        int ctl_name, int *nrels_mag, long *results);
248static void mtp008_pwm(struct i2c_client *client, int operation,
249                       int ctl_name, int *nrels_mag, long *results);
250static void mtp008_sens(struct i2c_client *client, int operation,
251                        int ctl_name, int *nrels_mag, long *results);
252static void mtp008_getsensortype(struct mtp008_data *data, u8 inp);
253
254static int mtp008_id = 0;
255
256static struct i2c_driver mtp008_driver =
257{
258        .owner          = THIS_MODULE,
259        .name           = "MTP008 sensor driver",
260        .id             = I2C_DRIVERID_MTP008,
261        .flags          = I2C_DF_NOTIFY,
262        .attach_adapter = mtp008_attach_adapter,
263        .detach_client  = mtp008_detach_client,
264};
265
266/* -- SENSORS SYSCTL START -- */
267#define MTP008_SYSCTL_IN0       1000    /* Volts * 100 */
268#define MTP008_SYSCTL_IN1       1001
269#define MTP008_SYSCTL_IN2       1002
270#define MTP008_SYSCTL_IN3       1003
271#define MTP008_SYSCTL_IN4       1004
272#define MTP008_SYSCTL_IN5       1005
273#define MTP008_SYSCTL_IN6       1006
274#define MTP008_SYSCTL_FAN1      1101    /* Rotations/min */
275#define MTP008_SYSCTL_FAN2      1102
276#define MTP008_SYSCTL_FAN3      1103
277#define MTP008_SYSCTL_TEMP1     1200    /* Degrees Celcius * 10 */
278#define MTP008_SYSCTL_TEMP2     1201    /* Degrees Celcius * 10 */
279#define MTP008_SYSCTL_TEMP3     1202    /* Degrees Celcius * 10 */
280#define MTP008_SYSCTL_VID       1300    /* Volts * 100 */
281#define MTP008_SYSCTL_PWM1      1401
282#define MTP008_SYSCTL_PWM2      1402
283#define MTP008_SYSCTL_PWM3      1403
284#define MTP008_SYSCTL_SENS1     1501    /* 1, 2, or Beta (3000-5000) */
285#define MTP008_SYSCTL_SENS2     1502
286#define MTP008_SYSCTL_SENS3     1503
287#define MTP008_SYSCTL_FAN_DIV   2000    /* 1, 2, 4 or 8 */
288#define MTP008_SYSCTL_ALARMS    2001    /* bitvector */
289#define MTP008_SYSCTL_BEEP      2002    /* bitvector */
290
291#define MTP008_ALARM_IN0        0x0001
292#define MTP008_ALARM_IN1        0x0002
293#define MTP008_ALARM_IN2        0x0004
294#define MTP008_ALARM_IN3        0x0008
295#define MTP008_ALARM_IN4        0x0100
296#define MTP008_ALARM_IN5        0x0200
297#define MTP008_ALARM_IN6        0x0400
298#define MTP008_ALARM_FAN1       0x0040
299#define MTP008_ALARM_FAN2       0x0080
300#define MTP008_ALARM_FAN3       0x0800
301#define MTP008_ALARM_TEMP1      0x0010
302#define MTP008_ALARM_TEMP2      0x0100
303#define MTP008_ALARM_TEMP3      0x0200
304
305/* -- SENSORS SYSCTL END -- */
306
307/* The /proc/sys entries */
308/* These files are created for each detected chip. This is just a template;
309   though at first sight, you might think we could use a statically
310   allocated list, we need some way to get back to the parent - which
311   is done through one of the 'extra' fields which are initialized
312   when a new copy is allocated. */
313
314static ctl_table mtp008_dir_table_template[] =
315{
316        {MTP008_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL,
317         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
318        {MTP008_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL,
319         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
320        {MTP008_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL,
321         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
322        {MTP008_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL,
323         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
324        {MTP008_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL,
325         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
326        {MTP008_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL,
327         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
328        {MTP008_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL,
329         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
330        {MTP008_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL,
331         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan},
332        {MTP008_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL,
333         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan},
334        {MTP008_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL,
335         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan},
336        {MTP008_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL,
337         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_temp},
338        {MTP008_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL,
339       &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_temp_add},
340        {MTP008_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL,
341       &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_temp_add},
342        {MTP008_SYSCTL_VID, "vid", NULL, 0, 0444, NULL,
343         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_vid},
344        {MTP008_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL,
345         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan_div},
346        {MTP008_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL,
347         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_alarms},
348        {MTP008_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL,
349         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_beep},
350        {MTP008_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL,
351         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_pwm},
352        {MTP008_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL,
353         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_pwm},
354        {MTP008_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL,
355         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_pwm},
356        {MTP008_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL,
357         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_sens},
358        {MTP008_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL,
359         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_sens},
360        {MTP008_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL,
361         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_sens},
362        {0}
363};
364
365/* This function is called when:
366 * mtp008_driver is inserted (when this module is loaded), for each available
367 * adapter when a new adapter is inserted (and mtp008_driver is still present)
368 */
369static int mtp008_attach_adapter(struct i2c_adapter *adapter)
370{
371        struct i2c_client_address_data mtp008_addr_data;
372
373        mtp008_addr_data.normal_i2c = addr_data.normal_i2c;
374        mtp008_addr_data.normal_i2c_range = addr_data.normal_i2c_range;
375        mtp008_addr_data.probe = addr_data.probe;
376        mtp008_addr_data.probe_range = addr_data.probe_range;
377        mtp008_addr_data.ignore = addr_data.ignore;
378        mtp008_addr_data.ignore_range = addr_data.ignore_range;
379        mtp008_addr_data.force = addr_data.forces->force;
380
381        return i2c_probe(adapter, &mtp008_addr_data, mtp008_detect);
382}
383
384int mtp008_detect(struct i2c_adapter *adapter, int address,
385                  unsigned short flags, int kind)
386{
387        const char *type_name = "";
388        const char *client_name = "";
389        int is_isa, err, sysid;
390        struct i2c_client *new_client;
391        struct mtp008_data *data;
392
393        err = 0;
394
395        is_isa = i2c_is_isa_adapter(adapter);
396        if (is_isa ||
397            !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
398                goto ERROR0;
399
400        /*
401         * We presume we have a valid client.  We now create the client
402         * structure, even though we cannot fill it completely yet.  But it
403         * allows us to use mtp008_(read|write)_value().
404         */
405        if (!(new_client = kmalloc(sizeof(struct i2c_client) +
406                                   sizeof(struct mtp008_data),
407                                   GFP_KERNEL))) {
408                err = -ENOMEM;
409                goto ERROR0;
410        }
411        data = (struct mtp008_data *) (new_client + 1);
412        new_client->addr = address;
413        new_client->data = data;
414        new_client->adapter = adapter;
415        new_client->driver = &mtp008_driver;
416        new_client->flags = 0;
417
418        /*
419         * Remaining detection.
420         */
421        if (kind < 0) {
422                if (mtp008_read_value(new_client, MTP008_REG_CHIPID) != 0xac)
423                        goto ERROR1;
424        }
425        /*
426         * Fill in the remaining client fields and put it into the global list.
427         */
428        type_name = "mtp008";
429        client_name = "MTP008 chip";
430        strcpy(new_client->name, client_name);
431        data->type = kind;
432
433        new_client->id = mtp008_id++;
434        data->valid = 0;
435        init_MUTEX(&data->update_lock);
436
437        /*
438         * Tell the I2C layer that a new client has arrived.
439         */
440        if ((err = i2c_attach_client(new_client)))
441                goto ERROR1;
442
443        /*
444         * Register a new directory entry with the sensors module.
445         */
446        if ((sysid = i2c_register_entry(new_client, type_name,
447                                            mtp008_dir_table_template)) < 0) {
448                err = sysid;
449                goto ERROR2;
450        }
451        data->sysctl_id = sysid;
452
453        /*
454         * Initialize the MTP008 chip.
455         */
456        mtp008_init_client(new_client);
457
458        return 0;
459
460        /*
461         * Error handling.  Bad programming practise but very code efficient.
462         */
463      ERROR2:
464        i2c_detach_client(new_client);
465      ERROR1:
466        kfree(new_client);
467
468      ERROR0:
469        return err;
470}
471
472static int mtp008_detach_client(struct i2c_client *client)
473{
474        int err;
475
476        i2c_deregister_entry(
477                ((struct mtp008_data *) (client->data))->sysctl_id);
478
479        if ((err = i2c_detach_client(client))) {
480                printk("mtp008.o: Deregistration failed, "
481                       "client not detached.\n");
482                return err;
483        }
484        kfree(client);
485
486        return 0;
487}
488
489
490static int mtp008_read_value(struct i2c_client *client, u8 reg)
491{
492        return i2c_smbus_read_byte_data(client, reg) & 0xff;
493}
494
495static int mtp008_write_value(struct i2c_client *client, u8 reg, u8 value)
496{
497        return i2c_smbus_write_byte_data(client, reg, value);
498}
499
500/* Called when we have found a new MTP008. It should set limits, etc. */
501static void mtp008_init_client(struct i2c_client *client)
502{
503        u8 save1, save2;
504        struct mtp008_data *data;
505
506        data = client->data;
507
508        /*
509         * Initialize the Myson MTP008 hardware monitoring chip.
510         * Save the pin settings that the BIOS hopefully set.
511         */
512        save1 = mtp008_read_value(client, MTP008_REG_PIN_CTRL1);
513        save2 = mtp008_read_value(client, MTP008_REG_PIN_CTRL2);
514        mtp008_write_value(client, MTP008_REG_CONFIG,
515             (mtp008_read_value(client, MTP008_REG_CONFIG) & 0x7f) | 0x80);
516        mtp008_write_value(client, MTP008_REG_PIN_CTRL1, save1);
517        mtp008_write_value(client, MTP008_REG_PIN_CTRL2, save2);
518
519        mtp008_getsensortype(data, save2);
520
521
522        /*
523         * Start monitoring.
524         */
525        mtp008_write_value(
526                client, MTP008_REG_CONFIG,
527                (mtp008_read_value(client, MTP008_REG_CONFIG) & 0xf7) | 0x01
528        );
529}
530
531static void mtp008_update_client(struct i2c_client *client)
532{
533        int i;
534        u8 inp;
535        struct mtp008_data *data;
536
537        data = client->data;
538
539        down(&data->update_lock);
540
541        if ((jiffies - data->last_updated > HZ + HZ / 2) ||
542            (jiffies < data->last_updated) || !data->valid) {
543#ifdef DEBUG
544                printk("Starting MTP008 update\n");
545#endif
546
547                /*
548                 * Read in the analog inputs.  We're reading AIN4 and AIN5 as
549                 * regular analog inputs, even though they may have been
550                 * configured as temperature readings instead.  Interpretation
551                 * of these values is done elsewhere.
552                 */
553                for (i = 0; i < 7; i++) {
554                        data->in[i] =
555                                mtp008_read_value(client, MTP008_REG_IN(i));
556                        data->in_max[i] =
557                                mtp008_read_value(client, MTP008_REG_IN_MAX(i));
558                        data->in_min[i] =
559                                mtp008_read_value(client, MTP008_REG_IN_MIN(i));
560                }
561
562                /*
563                 * Read the temperature sensor.
564                 */
565                data->temp = mtp008_read_value(client, MTP008_REG_TEMP);
566                data->temp_max = mtp008_read_value(client, MTP008_REG_TEMP_MAX);
567                data->temp_min = mtp008_read_value(client, MTP008_REG_TEMP_MIN);
568
569                /*
570                 * Read the first 2 fan dividers and the VID setting.  Read the
571                 * third fan divider from a different register.
572                 */
573                inp = mtp008_read_value(client, MTP008_REG_VID_FANDIV);
574                data->vid = inp & 0x0f;
575                data->vid |= (mtp008_read_value(client,
576                                     MTP008_REG_RESET_VID4) & 0x01) << 4;
577
578                data->fan_div[0] = (inp >> 4) & 0x03;
579                data->fan_div[1] = inp >> 6;
580                data->fan_div[2] =
581                        mtp008_read_value(client, MTP008_REG_PIN_CTRL1) >> 6;
582
583                /*
584                 * Read the interrupt status registers.
585                 */
586                data->alarms =
587                        (mtp008_read_value(client,
588                                           MTP008_REG_INT_STAT1) & 0xdf) |
589                        (mtp008_read_value(client,
590                                           MTP008_REG_INT_STAT2) & 0x0f) << 8;
591
592                /*
593                 * Read the beep control registers.
594                 */
595                data->beeps =
596                        (mtp008_read_value(client,
597                                           MTP008_REG_BEEP_CTRL1) & 0xdf) |
598                        (mtp008_read_value(client,
599                                           MTP008_REG_BEEP_CTRL2) & 0x8f) << 8;
600
601                /*
602                 * Read the sensor configuration.
603                 */
604                inp = mtp008_read_value(client, MTP008_REG_PIN_CTRL2);
605                mtp008_getsensortype(data, inp);
606                data->pwmenable = inp;
607
608                /*
609                 * Read the PWM registers if enabled.
610                 */
611                for (i = 1; i <= 3; i++)
612                {
613                        if(PWMENABLE_FROM_REG(i, inp))
614                                data->pwm[i-1] = mtp008_read_value(client,
615                                                  MTP008_REG_PWM_CTRL(i));
616                        else
617                                data->pwm[i-1] = 255;
618                }
619
620                /*
621                 * Read the fan sensors. Skip 3 if PWM1 enabled.
622                 */
623                for (i = 1; i <= 3; i++) {
624                        if(i == 3 && PWMENABLE_FROM_REG(1, inp)) {
625                                data->fan[2] = 0;
626                                data->fan_min[2] = 0;
627                        } else {
628                                data->fan[i-1] = mtp008_read_value(client,
629                                          MTP008_REG_FAN(i));
630                                data->fan_min[i-1] = mtp008_read_value(client,
631                                          MTP008_REG_FAN_MIN(i));
632                        }
633                }
634
635                data->last_updated = jiffies;
636                data->valid = 1;
637        }
638        up(&data->update_lock);
639}
640
641static void mtp008_getsensortype(struct mtp008_data *data, u8 inp)
642{
643        inp &= 0x0f;
644        data->sens[0] = (inp >> 3) + 2;                 /* 2 or 3 */
645        data->sens[1] = ((inp >> 1) & 0x03) + 1;        /* 1, 2 or 3 */
646        data->sens[2] = (inp & 0x01) + 1;               /* 1 or 2 */
647}
648
649/* The next few functions are the call-back functions of the /proc/sys and
650   sysctl files. Which function is used is defined in the ctl_table in
651   the extra1 field.
652   Each function must return the magnitude (power of 10 to divide the date
653   with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
654   put a maximum of *nrels elements in results reflecting the data of this
655   file, and set *nrels to the number it actually put in it, if operation==
656   SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
657   results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
658   Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
659   large enough (by checking the incoming value of *nrels). This is not very
660   good practice, but as long as you put less than about 5 values in results,
661   you can assume it is large enough. */
662void mtp008_in(struct i2c_client *client, int operation, int ctl_name,
663               int *nrels_mag, long *results)
664{
665        int nr;
666        struct mtp008_data *data;
667
668        nr = ctl_name - MTP008_SYSCTL_IN0;
669        data = client->data;
670
671        switch (operation) {
672        case SENSORS_PROC_REAL_INFO:
673                *nrels_mag = 2;
674
675                break;
676        case SENSORS_PROC_REAL_READ:
677                mtp008_update_client(client);
678
679                if((nr != 4 && nr != 5) || data->sens[nr - 3] == VOLTAGE) {
680                        results[0] = IN_FROM_REG(data->in_min[nr]);
681                        results[1] = IN_FROM_REG(data->in_max[nr]);
682                        results[2] = IN_FROM_REG(data->in[nr]);
683                } else {
684                        results[0] = 0;
685                        results[1] = 0;
686                        results[2] = 0;
687                }
688
689                *nrels_mag = 3;
690
691                break;
692        case SENSORS_PROC_REAL_WRITE:
693                if((nr != 4 && nr != 5) || data->sens[nr - 3] == VOLTAGE) {
694                        if (*nrels_mag >= 1) {
695                                data->in_min[nr] = IN_TO_REG(results[0]);
696                                mtp008_write_value(client, MTP008_REG_IN_MIN(nr),
697                                                   data->in_min[nr]);
698                        }
699                        if (*nrels_mag >= 2) {
700                                data->in_max[nr] = IN_TO_REG(results[1]);
701                                mtp008_write_value(client, MTP008_REG_IN_MAX(nr),
702                                                   data->in_max[nr]);
703                        }
704                }
705        }
706}
707
708void mtp008_fan(struct i2c_client *client, int operation, int ctl_name,
709                int *nrels_mag, long *results)
710{
711        int nr;
712        struct mtp008_data *data;
713
714        nr = ctl_name - MTP008_SYSCTL_FAN1;
715        data = client->data;
716
717        switch (operation) {
718        case SENSORS_PROC_REAL_INFO:
719                *nrels_mag = 0;
720
721                break;
722        case SENSORS_PROC_REAL_READ:
723                mtp008_update_client(client);
724
725                results[0] = FAN_FROM_REG(data->fan_min[nr],
726                                        DIV_FROM_REG(data->fan_div[nr]));
727                results[1] = FAN_FROM_REG(data->fan[nr],
728                                        DIV_FROM_REG(data->fan_div[nr]));
729
730                *nrels_mag = 2;
731
732                break;
733        case SENSORS_PROC_REAL_WRITE:
734                if (*nrels_mag >= 1) {
735                        data->fan_min[nr] =
736                            FAN_TO_REG(results[0],
737                                       DIV_FROM_REG(data->fan_div[nr]));
738                        mtp008_write_value(client, MTP008_REG_FAN_MIN(nr + 1),
739                                           data->fan_min[nr]);
740                }
741        }
742}
743
744void mtp008_temp(struct i2c_client *client, int operation, int ctl_name,
745                 int *nrels_mag, long *results)
746{
747        struct mtp008_data *data;
748
749        data = client->data;
750
751        switch (operation) {
752        case SENSORS_PROC_REAL_INFO:
753                *nrels_mag = 1;
754
755                break;
756        case SENSORS_PROC_REAL_READ:
757                mtp008_update_client(client);
758
759                results[0] = TEMP_FROM_REG(data->temp_max);
760                results[1] = TEMP_FROM_REG(data->temp_min);
761                results[2] = TEMP_FROM_REG(data->temp);
762                *nrels_mag = 3;
763
764                break;
765        case SENSORS_PROC_REAL_WRITE:
766                if (*nrels_mag >= 1) {
767                        data->temp_max = TEMP_TO_REG(results[0]);
768                        mtp008_write_value(client, MTP008_REG_TEMP_MAX,
769                                           data->temp_max);
770                }
771                if (*nrels_mag >= 2) {
772                        data->temp_min = TEMP_TO_REG(results[1]);
773                        mtp008_write_value(client, MTP008_REG_TEMP_MIN,
774                                           data->temp_min);
775                }
776        }
777}
778
779void mtp008_temp_add(struct i2c_client *client, int operation, int ctl_name,
780                     int *nrels_mag, long *results)
781{
782        int nr;
783        struct mtp008_data *data;
784
785        nr = 3 + ctl_name - MTP008_SYSCTL_TEMP1;        /* AIN4 or AIN5 */
786        data = client->data;
787
788        switch (operation) {
789        case SENSORS_PROC_REAL_INFO:
790                *nrels_mag = 1;
791
792                break;
793        case SENSORS_PROC_REAL_READ:
794                mtp008_update_client(client);
795
796                if(data->sens[nr - 3] != VOLTAGE) {
797                        results[0] = TEMP_FROM_REG(data->in_max[nr]);
798                        results[1] = TEMP_FROM_REG(data->in_min[nr]);
799                        results[2] = TEMP_FROM_REG(data->in[nr]);
800                } else {
801                        results[0] = 0;
802                        results[1] = 0;
803                        results[2] = 0;
804                }
805                *nrels_mag = 3;
806
807                break;
808        case SENSORS_PROC_REAL_WRITE:
809                if(data->sens[nr - 3] != VOLTAGE) {
810                        if (*nrels_mag >= 1) {
811                                data->in_max[nr] = TEMP_TO_REG(results[0]);
812                                mtp008_write_value(client, MTP008_REG_TEMP_MAX,
813                                                   data->in_max[nr]);
814                        }
815                        if (*nrels_mag >= 2) {
816                                data->in_min[nr] = TEMP_TO_REG(results[1]);
817                                mtp008_write_value(client, MTP008_REG_TEMP_MIN,
818                                                   data->in_min[nr]);
819                        }
820                }
821        }
822}
823
824void mtp008_vid(struct i2c_client *client, int operation, int ctl_name,
825                int *nrels_mag, long *results)
826{
827        struct mtp008_data *data;
828
829        data = client->data;
830
831        switch (operation) {
832        case SENSORS_PROC_REAL_INFO:
833                *nrels_mag = 2;
834
835                break;
836        case SENSORS_PROC_REAL_READ:
837                mtp008_update_client(client);
838
839                results[0] = VID_FROM_REG(data->vid);
840
841                *nrels_mag = 1;
842        }
843}
844
845void mtp008_fan_div(struct i2c_client *client, int operation,
846                    int ctl_name, int *nrels_mag, long *results)
847{
848        struct mtp008_data *data;
849        u8 val;
850
851        data = client->data;
852
853        switch (operation) {
854        case SENSORS_PROC_REAL_INFO:
855                *nrels_mag = 0;
856
857                break;
858        case SENSORS_PROC_REAL_READ:
859                mtp008_update_client(client);
860
861                results[0] = DIV_FROM_REG(data->fan_div[0]);
862                results[1] = DIV_FROM_REG(data->fan_div[1]);
863                results[2] = DIV_FROM_REG(data->fan_div[2]);
864
865                *nrels_mag = 3;
866
867                break;
868        case SENSORS_PROC_REAL_WRITE:
869                if (*nrels_mag >= 3) {
870                        data->fan_div[2] = DIV_TO_REG(results[2]);
871                        val = mtp008_read_value(client, MTP008_REG_PIN_CTRL1);
872                        val = (val & 0x3f) | (data->fan_div[2] & 0x03) << 6;
873                        mtp008_write_value(client, MTP008_REG_PIN_CTRL1, val);
874                }
875                if (*nrels_mag >= 1) {
876                        val = mtp008_read_value(client, MTP008_REG_VID_FANDIV);
877                        if (*nrels_mag >= 2) {
878                                data->fan_div[1] = DIV_TO_REG(results[1]);
879                                val = (val & 0x3f) |
880                                      (data->fan_div[1] & 0x03) << 6;
881                        }
882                        data->fan_div[0] = DIV_TO_REG(results[0]);
883                        val = (val & 0xcf) | (data->fan_div[0] & 0x03) << 4;
884                        mtp008_write_value(client, MTP008_REG_VID_FANDIV, val);
885                }
886        }
887}
888
889void mtp008_alarms(struct i2c_client *client, int operation, int ctl_name,
890                   int *nrels_mag, long *results)
891{
892        struct mtp008_data *data;
893
894        data = client->data;
895
896        switch (operation) {
897        case SENSORS_PROC_REAL_INFO:
898                *nrels_mag = 0;
899
900                break;
901        case SENSORS_PROC_REAL_READ:
902                mtp008_update_client(client);
903
904                results[0] = ALARMS_FROM_REG(data->alarms);
905
906                *nrels_mag = 1;
907        }
908}
909
910void mtp008_beep(struct i2c_client *client, int operation, int ctl_name,
911                 int *nrels_mag, long *results)
912{
913        struct mtp008_data *data;
914
915        data = client->data;
916
917        switch (operation) {
918        case SENSORS_PROC_REAL_INFO:
919                *nrels_mag = 0;
920
921                break;
922        case SENSORS_PROC_REAL_READ:
923                mtp008_update_client(client);
924
925                results[0] = BEEPS_FROM_REG(data->beeps);
926
927                *nrels_mag = 1;
928
929                break;
930        case SENSORS_PROC_REAL_WRITE:
931                if (*nrels_mag >= 1) {
932                        data->beeps = BEEPS_TO_REG(results[0]) & 0xdf8f;
933
934                        mtp008_write_value(client, MTP008_REG_BEEP_CTRL1,
935                                           data->beeps & 0xff);
936                        mtp008_write_value(client, MTP008_REG_BEEP_CTRL2,
937                                           data->beeps >> 8);
938                }
939        }
940}
941
942void mtp008_pwm(struct i2c_client *client, int operation, int ctl_name,
943                int *nrels_mag, long *results)
944{
945        int nr;
946        struct mtp008_data *data;
947
948        nr = ctl_name - MTP008_SYSCTL_PWM1;
949        data = client->data;
950
951        switch (operation) {
952        case SENSORS_PROC_REAL_INFO:
953                *nrels_mag = 0;
954
955                break;
956        case SENSORS_PROC_REAL_READ:
957                mtp008_update_client(client);
958
959                results[0] = PWM_FROM_REG(data->pwm[nr]);
960                results[1] = PWMENABLE_FROM_REG(nr + 1, data->pwmenable);
961                *nrels_mag = 2;
962
963                break;
964        case SENSORS_PROC_REAL_WRITE:
965                if (*nrels_mag >= 1) {
966                        if (*nrels_mag >= 2) {
967                                if(results[1])
968                                        data->pwmenable |= 0x10 << nr;
969                                else
970                                        data->pwmenable &= ~(0x10 << nr);
971                                mtp008_write_value(client, MTP008_REG_PIN_CTRL2,
972                                                   data->pwmenable);
973                        }
974                        data->pwm[nr] = PWM_TO_REG(results[0]);
975                        mtp008_write_value(client, MTP008_REG_PWM_CTRL(nr),
976                                           data->pwm[nr]);
977                }
978        }
979}
980
981void mtp008_sens(struct i2c_client *client, int operation, int ctl_name,
982                 int *nrels_mag, long *results)
983{
984        const char *opts = "";
985        int nr;
986        u8 tmp;
987        struct mtp008_data *data;
988
989        nr = 1 + ctl_name - MTP008_SYSCTL_SENS1;
990        data = client->data;
991
992        switch (operation) {
993        case SENSORS_PROC_REAL_INFO:
994                *nrels_mag = 0;
995
996                break;
997        case SENSORS_PROC_REAL_READ:
998                results[0] = data->sens[nr - 1];
999
1000                *nrels_mag = 1;
1001
1002                break;
1003        case SENSORS_PROC_REAL_WRITE:
1004                if (*nrels_mag >= 1) {
1005                        tmp = mtp008_read_value(client, MTP008_REG_PIN_CTRL2);
1006
1007                        switch (nr) {
1008                        case 1: /* VT or PII */
1009                                opts = "2 or 3";
1010
1011                                switch (results[0]) {
1012                                case THERMISTOR:
1013                                        mtp008_write_value(
1014                                                client, MTP008_REG_PIN_CTRL2,
1015                                                tmp & ~MTP008_CFG_VT1_PII);
1016                                        data->sens[0] = 2;
1017                                        return;
1018                                case PIIDIODE:
1019                                        mtp008_write_value(
1020                                                client, MTP008_REG_PIN_CTRL2,
1021                                                tmp | MTP008_CFG_VT1_PII);
1022                                        data->sens[0] = 3;
1023                                        return;
1024                                }
1025
1026                                break;
1027                        case 2: /* AIN, VT or PII */
1028                                tmp &= ~MTP008_CFG_VT2_MASK;
1029                                opts = "1, 2 or 3";
1030
1031                                switch (results[0]) {
1032                                case VOLTAGE:
1033                                        mtp008_write_value(
1034                                                client, MTP008_REG_PIN_CTRL2,
1035                                                tmp | MTP008_CFG_VT2_AIN);
1036                                        data->sens[1] = 1;
1037                                        return;
1038                                case THERMISTOR:
1039                                        mtp008_write_value(
1040                                                client, MTP008_REG_PIN_CTRL2,
1041                                                tmp | MTP008_CFG_VT2_VT);
1042                                        data->sens[1] = 2;
1043                                        return;
1044                                case PIIDIODE:
1045                                        mtp008_write_value(
1046                                                client, MTP008_REG_PIN_CTRL2,
1047                                                tmp | MTP008_CFG_VT2_PII);
1048                                        data->sens[1] = 3;
1049                                        return;
1050                                }
1051
1052                                break;
1053                        case 3: /* AIN or VT */
1054                                opts = "1 or 2";
1055
1056                                switch (results[0]) {
1057                                case VOLTAGE:
1058                                        mtp008_write_value(
1059                                                client, MTP008_REG_PIN_CTRL2,
1060                                                tmp & ~MTP008_CFG_VT3_VT);
1061                                        data->sens[2] = 1;
1062                                        return;
1063                                case THERMISTOR:
1064                                        mtp008_write_value(
1065                                                client, MTP008_REG_PIN_CTRL2,
1066                                                tmp | MTP008_CFG_VT3_VT);
1067                                        data->sens[2] = 2;
1068                                        return;
1069                                }
1070
1071                                break;
1072                        }
1073
1074                        printk("mtp008.o: Invalid sensor type %ld "
1075                               "for sensor %d; must be %s.\n",
1076                               results[0], nr, opts);
1077                }
1078        }
1079}
1080
1081static int __init sm_mtp008_init(void)
1082{
1083        printk("mtp008.o version %s (%s)\n", LM_VERSION, LM_DATE);
1084        return i2c_add_driver(&mtp008_driver);
1085}
1086
1087static void __exit sm_mtp008_exit(void)
1088{
1089        i2c_del_driver(&mtp008_driver);
1090}
1091
1092
1093
1094MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
1095              "Philip Edelbrock <phil@netroedge.com>, "
1096              "and Kris Van Hees <aedil@alchar.org>");
1097MODULE_DESCRIPTION("MTP008 driver");
1098
1099module_init(sm_mtp008_init);
1100module_exit(sm_mtp008_exit);
Note: See TracBrowser for help on using the browser.