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

Revision 2867, 29.5 KB (checked in by khali, 8 years ago)

Drop unused client id.

  • 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, 2004  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        struct i2c_client client;
197        int sysctl_id;
198        enum chips type;
199
200        struct semaphore update_lock;
201        char valid;                             /* !=0 if fields are valid */
202        unsigned long last_updated;             /* In jiffies */
203
204        u8 in[7];                               /* Register value */
205        u8 in_max[7];                           /* Register value */
206        u8 in_min[7];                           /* Register value */
207        u8 temp;                                /* Register value */
208        u8 temp_max;                            /* Register value */
209        u8 temp_min;                            /* Register value */
210        u8 fan[3];                              /* Register value */
211        u8 fan_min[3];                          /* Register value */
212        u8 vid;                                 /* Register encoding */
213        u8 fan_div[3];                          /* Register encoding */
214        u16 alarms;                             /* Register encoding */
215        u16 beeps;                              /* Register encoding */
216        u8 pwm[4];                              /* Register value */
217        u8 sens[3];                             /* 1 = Analog input,
218                                                   2 = Thermistor,
219                                                   3 = PII/Celeron diode */
220        u8 pwmenable;                           /* Register 0x57 value */
221};
222
223static int mtp008_attach_adapter(struct i2c_adapter *adapter);
224static int mtp008_detect(struct i2c_adapter *adapter, int address,
225                         unsigned short flags, int kind);
226static int mtp008_detach_client(struct i2c_client *client);
227
228static int mtp008_read_value(struct i2c_client *client, u8 register);
229static int mtp008_write_value(struct i2c_client *client, u8 register, u8 value);
230static void mtp008_update_client(struct i2c_client *client);
231static void mtp008_init_client(struct i2c_client *client);
232
233static void mtp008_in(struct i2c_client *client, int operation,
234                      int ctl_name, int *nrels_mag, long *results);
235static void mtp008_fan(struct i2c_client *client, int operation,
236                       int ctl_name, int *nrels_mag, long *results);
237static void mtp008_temp(struct i2c_client *client, int operation,
238                        int ctl_name, int *nrels_mag, long *results);
239static void mtp008_temp_add(struct i2c_client *client, int operation,
240                            int ctl_name, int *nrels_mag, long *results);
241static void mtp008_vid(struct i2c_client *client, int operation,
242                       int ctl_name, int *nrels_mag, long *results);
243static void mtp008_fan_div(struct i2c_client *client, int operation,
244                           int ctl_name, int *nrels_mag, long *results);
245static void mtp008_alarms(struct i2c_client *client, int operation,
246                          int ctl_name, int *nrels_mag, long *results);
247static void mtp008_beep(struct i2c_client *client, int operation,
248                        int ctl_name, int *nrels_mag, long *results);
249static void mtp008_pwm(struct i2c_client *client, int operation,
250                       int ctl_name, int *nrels_mag, long *results);
251static void mtp008_sens(struct i2c_client *client, int operation,
252                        int ctl_name, int *nrels_mag, long *results);
253static void mtp008_getsensortype(struct mtp008_data *data, u8 inp);
254
255static struct i2c_driver mtp008_driver =
256{
257        .name           = "MTP008 sensor driver",
258        .id             = I2C_DRIVERID_MTP008,
259        .flags          = I2C_DF_NOTIFY,
260        .attach_adapter = mtp008_attach_adapter,
261        .detach_client  = mtp008_detach_client,
262};
263
264/* -- SENSORS SYSCTL START -- */
265#define MTP008_SYSCTL_IN0       1000    /* Volts * 100 */
266#define MTP008_SYSCTL_IN1       1001
267#define MTP008_SYSCTL_IN2       1002
268#define MTP008_SYSCTL_IN3       1003
269#define MTP008_SYSCTL_IN4       1004
270#define MTP008_SYSCTL_IN5       1005
271#define MTP008_SYSCTL_IN6       1006
272#define MTP008_SYSCTL_FAN1      1101    /* Rotations/min */
273#define MTP008_SYSCTL_FAN2      1102
274#define MTP008_SYSCTL_FAN3      1103
275#define MTP008_SYSCTL_TEMP1     1200    /* Degrees Celcius * 10 */
276#define MTP008_SYSCTL_TEMP2     1201    /* Degrees Celcius * 10 */
277#define MTP008_SYSCTL_TEMP3     1202    /* Degrees Celcius * 10 */
278#define MTP008_SYSCTL_VID       1300    /* Volts * 100 */
279#define MTP008_SYSCTL_PWM1      1401
280#define MTP008_SYSCTL_PWM2      1402
281#define MTP008_SYSCTL_PWM3      1403
282#define MTP008_SYSCTL_SENS1     1501    /* 1, 2, or Beta (3000-5000) */
283#define MTP008_SYSCTL_SENS2     1502
284#define MTP008_SYSCTL_SENS3     1503
285#define MTP008_SYSCTL_FAN_DIV   2000    /* 1, 2, 4 or 8 */
286#define MTP008_SYSCTL_ALARMS    2001    /* bitvector */
287#define MTP008_SYSCTL_BEEP      2002    /* bitvector */
288
289#define MTP008_ALARM_IN0        0x0001
290#define MTP008_ALARM_IN1        0x0002
291#define MTP008_ALARM_IN2        0x0004
292#define MTP008_ALARM_IN3        0x0008
293#define MTP008_ALARM_IN4        0x0100
294#define MTP008_ALARM_IN5        0x0200
295#define MTP008_ALARM_IN6        0x0400
296#define MTP008_ALARM_FAN1       0x0040
297#define MTP008_ALARM_FAN2       0x0080
298#define MTP008_ALARM_FAN3       0x0800
299#define MTP008_ALARM_TEMP1      0x0010
300#define MTP008_ALARM_TEMP2      0x0100
301#define MTP008_ALARM_TEMP3      0x0200
302
303/* -- SENSORS SYSCTL END -- */
304
305/* The /proc/sys entries */
306/* These files are created for each detected chip. This is just a template;
307   though at first sight, you might think we could use a statically
308   allocated list, we need some way to get back to the parent - which
309   is done through one of the 'extra' fields which are initialized
310   when a new copy is allocated. */
311
312static ctl_table mtp008_dir_table_template[] =
313{
314        {MTP008_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL,
315         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
316        {MTP008_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL,
317         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
318        {MTP008_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL,
319         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
320        {MTP008_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL,
321         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
322        {MTP008_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL,
323         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
324        {MTP008_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL,
325         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
326        {MTP008_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL,
327         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
328        {MTP008_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL,
329         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan},
330        {MTP008_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL,
331         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan},
332        {MTP008_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL,
333         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan},
334        {MTP008_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL,
335         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_temp},
336        {MTP008_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL,
337         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_temp_add},
338        {MTP008_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL,
339         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_temp_add},
340        {MTP008_SYSCTL_VID, "vid", NULL, 0, 0444, NULL,
341         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_vid},
342        {MTP008_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL,
343         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan_div},
344        {MTP008_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL,
345         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_alarms},
346        {MTP008_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL,
347         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_beep},
348        {MTP008_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL,
349         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_pwm},
350        {MTP008_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL,
351         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_pwm},
352        {MTP008_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL,
353         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_pwm},
354        {MTP008_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL,
355         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_sens},
356        {MTP008_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL,
357         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_sens},
358        {MTP008_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL,
359         &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_sens},
360        {0}
361};
362
363/* This function is called when:
364 * mtp008_driver is inserted (when this module is loaded), for each available
365 * adapter when a new adapter is inserted (and mtp008_driver is still present)
366 */
367static int mtp008_attach_adapter(struct i2c_adapter *adapter)
368{
369        struct i2c_client_address_data mtp008_addr_data;
370
371        mtp008_addr_data.normal_i2c = addr_data.normal_i2c;
372        mtp008_addr_data.normal_i2c_range = addr_data.normal_i2c_range;
373        mtp008_addr_data.probe = addr_data.probe;
374        mtp008_addr_data.probe_range = addr_data.probe_range;
375        mtp008_addr_data.ignore = addr_data.ignore;
376        mtp008_addr_data.ignore_range = addr_data.ignore_range;
377        mtp008_addr_data.force = addr_data.forces->force;
378
379        return i2c_probe(adapter, &mtp008_addr_data, mtp008_detect);
380}
381
382int mtp008_detect(struct i2c_adapter *adapter, int address,
383                  unsigned short flags, int kind)
384{
385        const char *type_name = "";
386        const char *client_name = "";
387        int is_isa, err, sysid;
388        struct i2c_client *new_client;
389        struct mtp008_data *data;
390
391        err = 0;
392
393        is_isa = i2c_is_isa_adapter(adapter);
394        if (is_isa ||
395            !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
396                goto ERROR0;
397
398        /*
399         * We presume we have a valid client.  We now create the client
400         * structure, even though we cannot fill it completely yet.  But it
401         * allows us to use mtp008_(read|write)_value().
402         */
403        if (!(data = kmalloc(sizeof(struct mtp008_data), GFP_KERNEL))) {
404                err = -ENOMEM;
405                goto ERROR0;
406        }
407
408        new_client = &data->client;
409        new_client->addr = address;
410        new_client->data = data;
411        new_client->adapter = adapter;
412        new_client->driver = &mtp008_driver;
413        new_client->flags = 0;
414
415        /*
416         * Remaining detection.
417         */
418        if (kind < 0) {
419                if (mtp008_read_value(new_client, MTP008_REG_CHIPID) != 0xac)
420                        goto ERROR1;
421        }
422        /*
423         * Fill in the remaining client fields and put it into the global list.
424         */
425        type_name = "mtp008";
426        client_name = "MTP008 chip";
427        strcpy(new_client->name, client_name);
428        data->type = kind;
429        data->valid = 0;
430        init_MUTEX(&data->update_lock);
431
432        /*
433         * Tell the I2C layer that a new client has arrived.
434         */
435        if ((err = i2c_attach_client(new_client)))
436                goto ERROR1;
437
438        /*
439         * Register a new directory entry with the sensors module.
440         */
441        if ((sysid = i2c_register_entry(new_client, type_name,
442                                            mtp008_dir_table_template,
443                                            THIS_MODULE)) < 0) {
444                err = sysid;
445                goto ERROR2;
446        }
447        data->sysctl_id = sysid;
448
449        /*
450         * Initialize the MTP008 chip.
451         */
452        mtp008_init_client(new_client);
453
454        return 0;
455
456        /*
457         * Error handling.  Bad programming practise but very code efficient.
458         */
459      ERROR2:
460        i2c_detach_client(new_client);
461      ERROR1:
462        kfree(data);
463
464      ERROR0:
465        return err;
466}
467
468static int mtp008_detach_client(struct i2c_client *client)
469{
470        int err;
471
472        i2c_deregister_entry(
473                ((struct mtp008_data *) (client->data))->sysctl_id);
474
475        if ((err = i2c_detach_client(client))) {
476                printk("mtp008.o: Deregistration failed, "
477                       "client not detached.\n");
478                return err;
479        }
480        kfree(client->data);
481
482        return 0;
483}
484
485
486static int mtp008_read_value(struct i2c_client *client, u8 reg)
487{
488        return i2c_smbus_read_byte_data(client, reg) & 0xff;
489}
490
491static int mtp008_write_value(struct i2c_client *client, u8 reg, u8 value)
492{
493        return i2c_smbus_write_byte_data(client, reg, value);
494}
495
496/* Called when we have found a new MTP008. It should set limits, etc. */
497static void mtp008_init_client(struct i2c_client *client)
498{
499        u8 save1, save2;
500        struct mtp008_data *data;
501
502        data = client->data;
503
504        /*
505         * Initialize the Myson MTP008 hardware monitoring chip.
506         * Save the pin settings that the BIOS hopefully set.
507         */
508        save1 = mtp008_read_value(client, MTP008_REG_PIN_CTRL1);
509        save2 = mtp008_read_value(client, MTP008_REG_PIN_CTRL2);
510        mtp008_write_value(client, MTP008_REG_CONFIG,
511             (mtp008_read_value(client, MTP008_REG_CONFIG) & 0x7f) | 0x80);
512        mtp008_write_value(client, MTP008_REG_PIN_CTRL1, save1);
513        mtp008_write_value(client, MTP008_REG_PIN_CTRL2, save2);
514
515        mtp008_getsensortype(data, save2);
516
517
518        /*
519         * Start monitoring.
520         */
521        mtp008_write_value(
522                client, MTP008_REG_CONFIG,
523                (mtp008_read_value(client, MTP008_REG_CONFIG) & 0xf7) | 0x01
524        );
525}
526
527static void mtp008_update_client(struct i2c_client *client)
528{
529        int i;
530        u8 inp;
531        struct mtp008_data *data;
532
533        data = client->data;
534
535        down(&data->update_lock);
536
537        if ((jiffies - data->last_updated > HZ + HZ / 2) ||
538            (jiffies < data->last_updated) || !data->valid) {
539#ifdef DEBUG
540                printk("Starting MTP008 update\n");
541#endif
542
543                /*
544                 * Read in the analog inputs.  We're reading AIN4 and AIN5 as
545                 * regular analog inputs, even though they may have been
546                 * configured as temperature readings instead.  Interpretation
547                 * of these values is done elsewhere.
548                 */
549                for (i = 0; i < 7; i++) {
550                        data->in[i] =
551                                mtp008_read_value(client, MTP008_REG_IN(i));
552                        data->in_max[i] =
553                                mtp008_read_value(client, MTP008_REG_IN_MAX(i));
554                        data->in_min[i] =
555                                mtp008_read_value(client, MTP008_REG_IN_MIN(i));
556                }
557
558                /*
559                 * Read the temperature sensor.
560                 */
561                data->temp = mtp008_read_value(client, MTP008_REG_TEMP);
562                data->temp_max = mtp008_read_value(client, MTP008_REG_TEMP_MAX);
563                data->temp_min = mtp008_read_value(client, MTP008_REG_TEMP_MIN);
564
565                /*
566                 * Read the first 2 fan dividers and the VID setting.  Read the
567                 * third fan divider from a different register.
568                 */
569                inp = mtp008_read_value(client, MTP008_REG_VID_FANDIV);
570                data->vid = inp & 0x0f;
571                data->vid |= (mtp008_read_value(client,
572                                     MTP008_REG_RESET_VID4) & 0x01) << 4;
573
574                data->fan_div[0] = (inp >> 4) & 0x03;
575                data->fan_div[1] = inp >> 6;
576                data->fan_div[2] =
577                        mtp008_read_value(client, MTP008_REG_PIN_CTRL1) >> 6;
578
579                /*
580                 * Read the interrupt status registers.
581                 */
582                data->alarms =
583                        (mtp008_read_value(client,
584                                           MTP008_REG_INT_STAT1) & 0xdf) |
585                        (mtp008_read_value(client,
586                                           MTP008_REG_INT_STAT2) & 0x0f) << 8;
587
588                /*
589                 * Read the beep control registers.
590                 */
591                data->beeps =
592                        (mtp008_read_value(client,
593                                           MTP008_REG_BEEP_CTRL1) & 0xdf) |
594                        (mtp008_read_value(client,
595                                           MTP008_REG_BEEP_CTRL2) & 0x8f) << 8;
596
597                /*
598                 * Read the sensor configuration.
599                 */
600                inp = mtp008_read_value(client, MTP008_REG_PIN_CTRL2);
601                mtp008_getsensortype(data, inp);
602                data->pwmenable = inp;
603
604                /*
605                 * Read the PWM registers if enabled.
606                 */
607                for (i = 1; i <= 3; i++)
608                {
609                        if(PWMENABLE_FROM_REG(i, inp))
610                                data->pwm[i-1] = mtp008_read_value(client,
611                                                  MTP008_REG_PWM_CTRL(i));
612                        else
613                                data->pwm[i-1] = 255;
614                }
615
616                /*
617                 * Read the fan sensors. Skip 3 if PWM1 enabled.
618                 */
619                for (i = 1; i <= 3; i++) {
620                        if(i == 3 && PWMENABLE_FROM_REG(1, inp)) {
621                                data->fan[2] = 0;
622                                data->fan_min[2] = 0;
623                        } else {
624                                data->fan[i-1] = mtp008_read_value(client,
625                                          MTP008_REG_FAN(i));
626                                data->fan_min[i-1] = mtp008_read_value(client,
627                                          MTP008_REG_FAN_MIN(i));
628                        }
629                }
630
631                data->last_updated = jiffies;
632                data->valid = 1;
633        }
634        up(&data->update_lock);
635}
636
637static void mtp008_getsensortype(struct mtp008_data *data, u8 inp)
638{
639        inp &= 0x0f;
640        data->sens[0] = (inp >> 3) + 2;                 /* 2 or 3 */
641        data->sens[1] = ((inp >> 1) & 0x03) + 1;        /* 1, 2 or 3 */
642        data->sens[2] = (inp & 0x01) + 1;               /* 1 or 2 */
643}
644
645/* The next few functions are the call-back functions of the /proc/sys and
646   sysctl files. Which function is used is defined in the ctl_table in
647   the extra1 field.
648   Each function must return the magnitude (power of 10 to divide the date
649   with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
650   put a maximum of *nrels elements in results reflecting the data of this
651   file, and set *nrels to the number it actually put in it, if operation==
652   SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
653   results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
654   Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
655   large enough (by checking the incoming value of *nrels). This is not very
656   good practice, but as long as you put less than about 5 values in results,
657   you can assume it is large enough. */
658void mtp008_in(struct i2c_client *client, int operation, int ctl_name,
659               int *nrels_mag, long *results)
660{
661        int nr;
662        struct mtp008_data *data;
663
664        nr = ctl_name - MTP008_SYSCTL_IN0;
665        data = client->data;
666
667        switch (operation) {
668        case SENSORS_PROC_REAL_INFO:
669                *nrels_mag = 2;
670
671                break;
672        case SENSORS_PROC_REAL_READ:
673                mtp008_update_client(client);
674
675                if((nr != 4 && nr != 5) || data->sens[nr - 3] == VOLTAGE) {
676                        results[0] = IN_FROM_REG(data->in_min[nr]);
677                        results[1] = IN_FROM_REG(data->in_max[nr]);
678                        results[2] = IN_FROM_REG(data->in[nr]);
679                } else {
680                        results[0] = 0;
681                        results[1] = 0;
682                        results[2] = 0;
683                }
684
685                *nrels_mag = 3;
686
687                break;
688        case SENSORS_PROC_REAL_WRITE:
689                if((nr != 4 && nr != 5) || data->sens[nr - 3] == VOLTAGE) {
690                        if (*nrels_mag >= 1) {
691                                data->in_min[nr] = IN_TO_REG(results[0]);
692                                mtp008_write_value(client, MTP008_REG_IN_MIN(nr),
693                                                   data->in_min[nr]);
694                        }
695                        if (*nrels_mag >= 2) {
696                                data->in_max[nr] = IN_TO_REG(results[1]);
697                                mtp008_write_value(client, MTP008_REG_IN_MAX(nr),
698                                                   data->in_max[nr]);
699                        }
700                }
701        }
702}
703
704void mtp008_fan(struct i2c_client *client, int operation, int ctl_name,
705                int *nrels_mag, long *results)
706{
707        int nr;
708        struct mtp008_data *data;
709
710        nr = ctl_name - MTP008_SYSCTL_FAN1;
711        data = client->data;
712
713        switch (operation) {
714        case SENSORS_PROC_REAL_INFO:
715                *nrels_mag = 0;
716
717                break;
718        case SENSORS_PROC_REAL_READ:
719                mtp008_update_client(client);
720
721                results[0] = FAN_FROM_REG(data->fan_min[nr],
722                                        DIV_FROM_REG(data->fan_div[nr]));
723                results[1] = FAN_FROM_REG(data->fan[nr],
724                                        DIV_FROM_REG(data->fan_div[nr]));
725
726                *nrels_mag = 2;
727
728                break;
729        case SENSORS_PROC_REAL_WRITE:
730                if (*nrels_mag >= 1) {
731                        data->fan_min[nr] =
732                            FAN_TO_REG(results[0],
733                                       DIV_FROM_REG(data->fan_div[nr]));
734                        mtp008_write_value(client, MTP008_REG_FAN_MIN(nr + 1),
735                                           data->fan_min[nr]);
736                }
737        }
738}
739
740void mtp008_temp(struct i2c_client *client, int operation, int ctl_name,
741                 int *nrels_mag, long *results)
742{
743        struct mtp008_data *data;
744
745        data = client->data;
746
747        switch (operation) {
748        case SENSORS_PROC_REAL_INFO:
749                *nrels_mag = 1;
750
751                break;
752        case SENSORS_PROC_REAL_READ:
753                mtp008_update_client(client);
754
755                results[0] = TEMP_FROM_REG(data->temp_max);
756                results[1] = TEMP_FROM_REG(data->temp_min);
757                results[2] = TEMP_FROM_REG(data->temp);
758                *nrels_mag = 3;
759
760                break;
761        case SENSORS_PROC_REAL_WRITE:
762                if (*nrels_mag >= 1) {
763                        data->temp_max = TEMP_TO_REG(results[0]);
764                        mtp008_write_value(client, MTP008_REG_TEMP_MAX,
765                                           data->temp_max);
766                }
767                if (*nrels_mag >= 2) {
768                        data->temp_min = TEMP_TO_REG(results[1]);
769                        mtp008_write_value(client, MTP008_REG_TEMP_MIN,
770                                           data->temp_min);
771                }
772        }
773}
774
775void mtp008_temp_add(struct i2c_client *client, int operation, int ctl_name,
776                     int *nrels_mag, long *results)
777{
778        int nr;
779        struct mtp008_data *data;
780
781        nr = 3 + ctl_name - MTP008_SYSCTL_TEMP1;        /* AIN4 or AIN5 */
782        data = client->data;
783
784        switch (operation) {
785        case SENSORS_PROC_REAL_INFO:
786                *nrels_mag = 1;
787
788                break;
789        case SENSORS_PROC_REAL_READ:
790                mtp008_update_client(client);
791
792                if(data->sens[nr - 3] != VOLTAGE) {
793                        results[0] = TEMP_FROM_REG(data->in_max[nr]);
794                        results[1] = TEMP_FROM_REG(data->in_min[nr]);
795                        results[2] = TEMP_FROM_REG(data->in[nr]);
796                } else {
797                        results[0] = 0;
798                        results[1] = 0;
799                        results[2] = 0;
800                }
801                *nrels_mag = 3;
802
803                break;
804        case SENSORS_PROC_REAL_WRITE:
805                if(data->sens[nr - 3] != VOLTAGE) {
806                        if (*nrels_mag >= 1) {
807                                data->in_max[nr] = TEMP_TO_REG(results[0]);
808                                mtp008_write_value(client,
809                                                   MTP008_REG_IN_MAX(nr),
810                                                   data->in_max[nr]);
811                        }
812                        if (*nrels_mag >= 2) {
813                                data->in_min[nr] = TEMP_TO_REG(results[1]);
814                                mtp008_write_value(client,
815                                                   MTP008_REG_IN_MIN(nr),
816                                                   data->in_min[nr]);
817                        }
818                }
819        }
820}
821
822void mtp008_vid(struct i2c_client *client, int operation, int ctl_name,
823                int *nrels_mag, long *results)
824{
825        struct mtp008_data *data;
826
827        data = client->data;
828
829        switch (operation) {
830        case SENSORS_PROC_REAL_INFO:
831                *nrels_mag = 2;
832
833                break;
834        case SENSORS_PROC_REAL_READ:
835                mtp008_update_client(client);
836
837                results[0] = VID_FROM_REG(data->vid);
838
839                *nrels_mag = 1;
840        }
841}
842
843void mtp008_fan_div(struct i2c_client *client, int operation,
844                    int ctl_name, int *nrels_mag, long *results)
845{
846        struct mtp008_data *data;
847        u8 val;
848
849        data = client->data;
850
851        switch (operation) {
852        case SENSORS_PROC_REAL_INFO:
853                *nrels_mag = 0;
854
855                break;
856        case SENSORS_PROC_REAL_READ:
857                mtp008_update_client(client);
858
859                results[0] = DIV_FROM_REG(data->fan_div[0]);
860                results[1] = DIV_FROM_REG(data->fan_div[1]);
861                results[2] = DIV_FROM_REG(data->fan_div[2]);
862
863                *nrels_mag = 3;
864
865                break;
866        case SENSORS_PROC_REAL_WRITE:
867                if (*nrels_mag >= 3) {
868                        data->fan_div[2] = DIV_TO_REG(results[2]);
869                        val = mtp008_read_value(client, MTP008_REG_PIN_CTRL1);
870                        val = (val & 0x3f) | (data->fan_div[2] & 0x03) << 6;
871                        mtp008_write_value(client, MTP008_REG_PIN_CTRL1, val);
872                }
873                if (*nrels_mag >= 1) {
874                        val = mtp008_read_value(client, MTP008_REG_VID_FANDIV);
875                        if (*nrels_mag >= 2) {
876                                data->fan_div[1] = DIV_TO_REG(results[1]);
877                                val = (val & 0x3f) |
878                                      (data->fan_div[1] & 0x03) << 6;
879                        }
880                        data->fan_div[0] = DIV_TO_REG(results[0]);
881                        val = (val & 0xcf) | (data->fan_div[0] & 0x03) << 4;
882                        mtp008_write_value(client, MTP008_REG_VID_FANDIV, val);
883                }
884        }
885}
886
887void mtp008_alarms(struct i2c_client *client, int operation, int ctl_name,
888                   int *nrels_mag, long *results)
889{
890        struct mtp008_data *data;
891
892        data = client->data;
893
894        switch (operation) {
895        case SENSORS_PROC_REAL_INFO:
896                *nrels_mag = 0;
897
898                break;
899        case SENSORS_PROC_REAL_READ:
900                mtp008_update_client(client);
901
902                results[0] = ALARMS_FROM_REG(data->alarms);
903
904                *nrels_mag = 1;
905        }
906}
907
908void mtp008_beep(struct i2c_client *client, int operation, int ctl_name,
909                 int *nrels_mag, long *results)
910{
911        struct mtp008_data *data;
912
913        data = client->data;
914
915        switch (operation) {
916        case SENSORS_PROC_REAL_INFO:
917                *nrels_mag = 0;
918
919                break;
920        case SENSORS_PROC_REAL_READ:
921                mtp008_update_client(client);
922
923                results[0] = BEEPS_FROM_REG(data->beeps);
924
925                *nrels_mag = 1;
926
927                break;
928        case SENSORS_PROC_REAL_WRITE:
929                if (*nrels_mag >= 1) {
930                        data->beeps = BEEPS_TO_REG(results[0]) & 0xdf8f;
931
932                        mtp008_write_value(client, MTP008_REG_BEEP_CTRL1,
933                                           data->beeps & 0xff);
934                        mtp008_write_value(client, MTP008_REG_BEEP_CTRL2,
935                                           data->beeps >> 8);
936                }
937        }
938}
939
940void mtp008_pwm(struct i2c_client *client, int operation, int ctl_name,
941                int *nrels_mag, long *results)
942{
943        int nr;
944        struct mtp008_data *data;
945
946        nr = ctl_name - MTP008_SYSCTL_PWM1;
947        data = client->data;
948
949        switch (operation) {
950        case SENSORS_PROC_REAL_INFO:
951                *nrels_mag = 0;
952
953                break;
954        case SENSORS_PROC_REAL_READ:
955                mtp008_update_client(client);
956
957                results[0] = PWM_FROM_REG(data->pwm[nr]);
958                results[1] = PWMENABLE_FROM_REG(nr + 1, data->pwmenable);
959                *nrels_mag = 2;
960
961                break;
962        case SENSORS_PROC_REAL_WRITE:
963                if (*nrels_mag >= 1) {
964                        if (*nrels_mag >= 2) {
965                                if(results[1])
966                                        data->pwmenable |= 0x10 << nr;
967                                else
968                                        data->pwmenable &= ~(0x10 << nr);
969                                mtp008_write_value(client, MTP008_REG_PIN_CTRL2,
970                                                   data->pwmenable);
971                        }
972                        data->pwm[nr] = PWM_TO_REG(results[0]);
973                        mtp008_write_value(client, MTP008_REG_PWM_CTRL(nr),
974                                           data->pwm[nr]);
975                }
976        }
977}
978
979void mtp008_sens(struct i2c_client *client, int operation, int ctl_name,
980                 int *nrels_mag, long *results)
981{
982        const char *opts = "";
983        int nr;
984        u8 tmp;
985        struct mtp008_data *data;
986
987        nr = 1 + ctl_name - MTP008_SYSCTL_SENS1;
988        data = client->data;
989
990        switch (operation) {
991        case SENSORS_PROC_REAL_INFO:
992                *nrels_mag = 0;
993
994                break;
995        case SENSORS_PROC_REAL_READ:
996                results[0] = data->sens[nr - 1];
997
998                *nrels_mag = 1;
999
1000                break;
1001        case SENSORS_PROC_REAL_WRITE:
1002                if (*nrels_mag >= 1) {
1003                        tmp = mtp008_read_value(client, MTP008_REG_PIN_CTRL2);
1004
1005                        switch (nr) {
1006                        case 1: /* VT or PII */
1007                                opts = "2 or 3";
1008
1009                                switch (results[0]) {
1010                                case THERMISTOR:
1011                                        mtp008_write_value(
1012                                                client, MTP008_REG_PIN_CTRL2,
1013                                                tmp & ~MTP008_CFG_VT1_PII);
1014                                        data->sens[0] = 2;
1015                                        return;
1016                                case PIIDIODE:
1017                                        mtp008_write_value(
1018                                                client, MTP008_REG_PIN_CTRL2,
1019                                                tmp | MTP008_CFG_VT1_PII);
1020                                        data->sens[0] = 3;
1021                                        return;
1022                                }
1023
1024                                break;
1025                        case 2: /* AIN, VT or PII */
1026                                tmp &= ~MTP008_CFG_VT2_MASK;
1027                                opts = "1, 2 or 3";
1028
1029                                switch (results[0]) {
1030                                case VOLTAGE:
1031                                        mtp008_write_value(
1032                                                client, MTP008_REG_PIN_CTRL2,
1033                                                tmp | MTP008_CFG_VT2_AIN);
1034                                        data->sens[1] = 1;
1035                                        return;
1036                                case THERMISTOR:
1037                                        mtp008_write_value(
1038                                                client, MTP008_REG_PIN_CTRL2,
1039                                                tmp | MTP008_CFG_VT2_VT);
1040                                        data->sens[1] = 2;
1041                                        return;
1042                                case PIIDIODE:
1043                                        mtp008_write_value(
1044                                                client, MTP008_REG_PIN_CTRL2,
1045                                                tmp | MTP008_CFG_VT2_PII);
1046                                        data->sens[1] = 3;
1047                                        return;
1048                                }
1049
1050                                break;
1051                        case 3: /* AIN or VT */
1052                                opts = "1 or 2";
1053
1054                                switch (results[0]) {
1055                                case VOLTAGE:
1056                                        mtp008_write_value(
1057                                                client, MTP008_REG_PIN_CTRL2,
1058                                                tmp & ~MTP008_CFG_VT3_VT);
1059                                        data->sens[2] = 1;
1060                                        return;
1061                                case THERMISTOR:
1062                                        mtp008_write_value(
1063                                                client, MTP008_REG_PIN_CTRL2,
1064                                                tmp | MTP008_CFG_VT3_VT);
1065                                        data->sens[2] = 2;
1066                                        return;
1067                                }
1068
1069                                break;
1070                        }
1071
1072                        printk("mtp008.o: Invalid sensor type %ld "
1073                               "for sensor %d; must be %s.\n",
1074                               results[0], nr, opts);
1075                }
1076        }
1077}
1078
1079static int __init sm_mtp008_init(void)
1080{
1081        printk("mtp008.o version %s (%s)\n", LM_VERSION, LM_DATE);
1082        return i2c_add_driver(&mtp008_driver);
1083}
1084
1085static void __exit sm_mtp008_exit(void)
1086{
1087        i2c_del_driver(&mtp008_driver);
1088}
1089
1090
1091
1092MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
1093              "Philip Edelbrock <phil@netroedge.com>, "
1094              "and Kris Van Hees <aedil@alchar.org>");
1095MODULE_DESCRIPTION("MTP008 driver");
1096
1097module_init(sm_mtp008_init);
1098module_exit(sm_mtp008_exit);
Note: See TracBrowser for help on using the browser.