root/lm-sensors/trunk/kernel/chips/smsc47m1.c @ 1466

Revision 1466, 15.2 KB (checked in by mds, 12 years ago)

fix driver name in struct i2c_driver

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    smsc47m1.c - Part of lm_sensors, Linux kernel modules
3                for hardware monitoring
4               
5    Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include <linux/version.h>
23#include <linux/module.h>
24#include <linux/slab.h>
25#include <linux/proc_fs.h>
26#include <linux/ioport.h>
27#include <linux/sysctl.h>
28#include <asm/errno.h>
29#include <asm/io.h>
30#include <linux/types.h>
31#include <linux/i2c.h>
32#include "version.h"
33#include "sensors.h"
34#include <linux/init.h>
35
36#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \
37    (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0))
38#define init_MUTEX(s) do { *(s) = MUTEX; } while(0)
39#endif
40
41#ifndef I2C_DRIVERID_SMSC47M1
42#define I2C_DRIVERID_SMSC47M1 1031
43#endif
44
45#ifndef THIS_MODULE
46#define THIS_MODULE NULL
47#endif
48
49static int force_addr = 0;
50MODULE_PARM(force_addr, "i");
51MODULE_PARM_DESC(force_addr,
52                 "Initialize the base address of the sensors");
53
54static unsigned short normal_i2c[] = { SENSORS_I2C_END };
55static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
56static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END };
57static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
58
59SENSORS_INSMOD_1(smsc47m1);
60
61/* modified from kernel/include/traps.c */
62#define REG     0x2e    /* The register to read/write */
63#define DEV     0x07    /* Register: Logical device select */
64#define VAL     0x2f    /* The value to read/write */
65#define PME     0x0a    /* The device with the fan registers in it */
66#define DEVID   0x20    /* Register: Device ID */
67
68static inline void
69superio_outb(int reg, int val)
70{
71        outb(reg, REG);
72        outb(val, VAL);
73}
74
75static inline int
76superio_inb(int reg)
77{
78        outb(reg, REG);
79        return inb(VAL);
80}
81
82static inline void
83superio_select(void)
84{
85        outb(DEV, REG);
86        outb(PME, VAL);
87}
88
89static inline void
90superio_enter(void)
91{
92        outb(0x55, REG);
93}
94
95static inline void
96superio_exit(void)
97{
98        outb(0xAA, REG);
99}
100
101#define SMSC_DEVID 0x59
102#define SMSC_ACT_REG 0x20
103#define SMSC_BASE_REG 0x60
104
105#define SMSC_EXTENT 0x80
106
107#define SMSC47M1_REG_ALARM1 0x04
108#define SMSC47M1_REG_TPIN2 0x33
109#define SMSC47M1_REG_TPIN1 0x34
110#define SMSC47M1_REG_PPIN(nr) (0x37 - (nr))
111#define SMSC47M1_REG_PWM(nr) (0x55 + (nr))
112#define SMSC47M1_REG_FANDIV 0x58
113#define SMSC47M1_REG_FAN(nr) (0x58 + (nr))
114#define SMSC47M1_REG_FAN_MIN(nr) (0x5a + (nr))
115
116extern inline u8 MIN_TO_REG(long rpm, int div)
117{
118        if (rpm == 0)
119                return 0;
120        rpm = SENSORS_LIMIT(rpm, 1, 1000000);
121        return SENSORS_LIMIT(192 - ((983040 + rpm * div / 2) / (rpm * div)),
122                             0, 191);
123}
124
125#define MIN_FROM_REG(val,div) ((val)>=192?0: \
126                                983040/((192-(val))*(div)))
127#define FAN_FROM_REG(val,div,preload) ((val)==0?-1:(val)==255?0: \
128                                983040/(((val)-preload)*(div)))
129#define DIV_FROM_REG(val) (1 << (val))
130#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
131#define PWM_FROM_REG(val) ((((val) & 0x7f) * 1005) / 640)
132#define PWM_TO_REG(val) SENSORS_LIMIT((((val) * 645) / 1000), 0, 63)
133
134#define SMSC47M1_INIT_FAN_MIN_1 3000
135#define SMSC47M1_INIT_FAN_MIN_2 3000
136
137#ifdef MODULE
138extern int init_module(void);
139extern int cleanup_module(void);
140#endif                          /* MODULE */
141
142struct smsc47m1_data {
143        struct semaphore lock;
144        int sysctl_id;
145
146        struct semaphore update_lock;
147        char valid;             /* !=0 if following fields are valid */
148        unsigned long last_updated;     /* In jiffies */
149
150        u8 fan[2];              /* Register value */
151        u8 fan_min[2];          /* Register value */
152        u8 fan_div[2];          /* Register encoding, shifted right */
153        u8 alarms;              /* Register encoding */
154        u8 pwm[2];              /* Register value (bit 7 is enable) */
155};
156
157#ifdef MODULE
158static
159#else
160extern
161#endif
162int __init sensors_smsc47m1_init(void);
163static int __init smsc47m1_cleanup(void);
164
165static int smsc47m1_attach_adapter(struct i2c_adapter *adapter);
166static int smsc47m1_detect(struct i2c_adapter *adapter, int address,
167                          unsigned short flags, int kind);
168static int smsc47m1_detach_client(struct i2c_client *client);
169static int smsc47m1_command(struct i2c_client *client, unsigned int cmd,
170                           void *arg);
171static void smsc47m1_inc_use(struct i2c_client *client);
172static void smsc47m1_dec_use(struct i2c_client *client);
173
174static int smsc47m1_read_value(struct i2c_client *client, u8 register);
175static int smsc47m1_write_value(struct i2c_client *client, u8 register,
176                               u8 value);
177static void smsc47m1_update_client(struct i2c_client *client);
178static void smsc47m1_init_client(struct i2c_client *client);
179static int smsc47m1_find(int *address);
180
181
182static void smsc47m1_fan(struct i2c_client *client, int operation,
183                        int ctl_name, int *nrels_mag, long *results);
184static void smsc47m1_alarms(struct i2c_client *client, int operation,
185                           int ctl_name, int *nrels_mag, long *results);
186static void smsc47m1_fan_div(struct i2c_client *client, int operation,
187                            int ctl_name, int *nrels_mag, long *results);
188static void smsc47m1_pwm(struct i2c_client *client, int operation,
189                        int ctl_name, int *nrels_mag, long *results);
190
191static int smsc47m1_id = 0;
192
193static struct i2c_driver smsc47m1_driver = {
194        /* name */ "SMSC47M1xx fan driver",
195        /* id */ I2C_DRIVERID_SMSC47M1,
196        /* flags */ I2C_DF_NOTIFY,
197        /* attach_adapter */ &smsc47m1_attach_adapter,
198        /* detach_client */ &smsc47m1_detach_client,
199        /* command */ &smsc47m1_command,
200        /* inc_use */ &smsc47m1_inc_use,
201        /* dec_use */ &smsc47m1_dec_use
202};
203
204static int __initdata smsc47m1_initialized = 0;
205
206static ctl_table smsc47m1_dir_table_template[] = {
207        {SMSC47M1_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
208         &i2c_sysctl_real, NULL, &smsc47m1_fan},
209        {SMSC47M1_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
210         &i2c_sysctl_real, NULL, &smsc47m1_fan},
211        {SMSC47M1_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
212         &i2c_sysctl_real, NULL, &smsc47m1_fan_div},
213        {SMSC47M1_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
214         &i2c_sysctl_real, NULL, &smsc47m1_alarms},
215        {SMSC47M1_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
216         &i2c_sysctl_real, NULL, &smsc47m1_pwm},
217        {SMSC47M1_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
218         &i2c_sysctl_real, NULL, &smsc47m1_pwm},
219        {0}
220};
221
222int smsc47m1_attach_adapter(struct i2c_adapter *adapter)
223{
224        return i2c_detect(adapter, &addr_data, smsc47m1_detect);
225}
226
227int smsc47m1_find(int *address)
228{
229        u16 val;
230
231        superio_enter();
232        val= superio_inb(DEVID);
233        if(SMSC_DEVID != val) {
234                superio_exit();
235                return -ENODEV;
236        }
237
238        superio_select();
239        val = (superio_inb(SMSC_BASE_REG) << 8) |
240               superio_inb(SMSC_BASE_REG + 1);
241        *address = val & ~(SMSC_EXTENT - 1);
242        if (*address == 0 && force_addr == 0) {
243                printk("smsc47m1.o: base address not set - use force_addr=0xaddr\n");
244                superio_exit();
245                return -ENODEV;
246        }
247        if (force_addr)
248                *address = force_addr;  /* so detect will get called */
249
250        superio_exit();
251        return 0;
252}
253
254int smsc47m1_detect(struct i2c_adapter *adapter, int address,
255                   unsigned short flags, int kind)
256{
257        int i;
258        struct i2c_client *new_client;
259        struct smsc47m1_data *data;
260        int err = 0;
261        const char *type_name = "smsc47m1";
262        const char *client_name = "SMSC47M11xx chip";
263
264        if (!i2c_is_isa_adapter(adapter)) {
265                return 0;
266        }
267
268        if(force_addr)
269                address = force_addr & ~(SMSC_EXTENT - 1);
270        if (check_region(address, SMSC_EXTENT)) {
271                printk("smsc47m1.o: region 0x%x already in use!\n", address);
272                return -ENODEV;
273        }
274        if(force_addr) {
275                printk("smsc47m1.o: forcing ISA address 0x%04X\n", address);
276                superio_enter();
277                superio_select();
278                superio_outb(SMSC_BASE_REG, address >> 8);
279                superio_outb(SMSC_BASE_REG+1, address & 0xff);
280                superio_exit();
281        }
282
283        if (!(new_client = kmalloc(sizeof(struct i2c_client) +
284                                   sizeof(struct smsc47m1_data),
285                                   GFP_KERNEL))) {
286                return -ENOMEM;
287        }
288
289        data = (struct smsc47m1_data *) (new_client + 1);
290        new_client->addr = address;
291        init_MUTEX(&data->lock);
292        new_client->data = data;
293        new_client->adapter = adapter;
294        new_client->driver = &smsc47m1_driver;
295        new_client->flags = 0;
296
297        request_region(address, SMSC_EXTENT, "smsc47m1x-fans");
298        strcpy(new_client->name, client_name);
299
300        new_client->id = smsc47m1_id++;
301        data->valid = 0;
302        init_MUTEX(&data->update_lock);
303
304        if ((err = i2c_attach_client(new_client)))
305                goto ERROR3;
306
307        if ((i = i2c_register_entry((struct i2c_client *) new_client,
308                                        type_name,
309                                        smsc47m1_dir_table_template,
310                                        THIS_MODULE)) < 0) {
311                err = i;
312                goto ERROR4;
313        }
314        data->sysctl_id = i;
315
316        smsc47m1_init_client(new_client);
317        return 0;
318
319      ERROR4:
320        i2c_detach_client(new_client);
321      ERROR3:
322        release_region(address, SMSC_EXTENT);
323        kfree(new_client);
324        return err;
325}
326
327int smsc47m1_detach_client(struct i2c_client *client)
328{
329        int err;
330
331        i2c_deregister_entry(((struct smsc47m1_data *) (client->data))->
332                                 sysctl_id);
333
334        if ((err = i2c_detach_client(client))) {
335                printk
336                    ("smsc47m1.o: Client deregistration failed, client not detached.\n");
337                return err;
338        }
339
340        release_region(client->addr, SMSC_EXTENT);
341        kfree(client);
342
343        return 0;
344}
345
346int smsc47m1_command(struct i2c_client *client, unsigned int cmd, void *arg)
347{
348        return 0;
349}
350
351void smsc47m1_inc_use(struct i2c_client *client)
352{
353#ifdef MODULE
354        MOD_INC_USE_COUNT;
355#endif
356}
357
358void smsc47m1_dec_use(struct i2c_client *client)
359{
360#ifdef MODULE
361        MOD_DEC_USE_COUNT;
362#endif
363}
364
365int smsc47m1_read_value(struct i2c_client *client, u8 reg)
366{
367        int res;
368
369        res = inb_p(client->addr + reg);
370        return res;
371}
372
373int smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value)
374{
375        outb_p(value, client->addr + reg);
376        return 0;
377}
378
379void smsc47m1_init_client(struct i2c_client *client)
380{
381        /* configure pins for tach function */
382        smsc47m1_write_value(client, SMSC47M1_REG_TPIN1, 0x05);
383        smsc47m1_write_value(client, SMSC47M1_REG_TPIN2, 0x05);
384        smsc47m1_write_value(client, SMSC47M1_REG_FAN_MIN(1),
385                            MIN_TO_REG(SMSC47M1_INIT_FAN_MIN_1, 2));
386        smsc47m1_write_value(client, SMSC47M1_REG_FAN_MIN(2),
387                            MIN_TO_REG(SMSC47M1_INIT_FAN_MIN_2, 2));
388}
389
390void smsc47m1_update_client(struct i2c_client *client)
391{
392        struct smsc47m1_data *data = client->data;
393        int i;
394
395        down(&data->update_lock);
396
397        if ((jiffies - data->last_updated > HZ + HZ / 2) ||
398            (jiffies < data->last_updated) || !data->valid) {
399                for (i = 1; i <= 2; i++) {
400                        data->fan[i - 1] =
401                            smsc47m1_read_value(client, SMSC47M1_REG_FAN(i));
402                        data->fan_min[i - 1] =
403                            smsc47m1_read_value(client, SMSC47M1_REG_FAN_MIN(i));
404                        data->pwm[i - 1] =
405                            smsc47m1_read_value(client, SMSC47M1_REG_PWM(i));
406                }
407
408                i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV);
409                data->fan_div[0] = (i >> 4) & 0x03;
410                data->fan_div[1] = i >> 6;
411                data->alarms =
412                        smsc47m1_read_value(client, SMSC47M1_REG_ALARM1) >> 6;
413                if(data->alarms)
414                        smsc47m1_write_value(client, SMSC47M1_REG_ALARM1, 0xc0);
415                data->last_updated = jiffies;
416                data->valid = 1;
417        }
418
419        up(&data->update_lock);
420}
421
422
423void smsc47m1_fan(struct i2c_client *client, int operation, int ctl_name,
424                 int *nrels_mag, long *results)
425{
426        struct smsc47m1_data *data = client->data;
427        int nr = ctl_name - SMSC47M1_SYSCTL_FAN1 + 1;
428
429        if (operation == SENSORS_PROC_REAL_INFO)
430                *nrels_mag = 0;
431        else if (operation == SENSORS_PROC_REAL_READ) {
432                smsc47m1_update_client(client);
433                results[0] = MIN_FROM_REG(data->fan_min[nr - 1],
434                                          DIV_FROM_REG(data->fan_div[nr - 1]));
435                results[1] = FAN_FROM_REG(data->fan[nr - 1],
436                                          DIV_FROM_REG(data->fan_div[nr - 1]),
437                                          data->fan_min[nr - 1]);
438                *nrels_mag = 2;
439        } else if (operation == SENSORS_PROC_REAL_WRITE) {
440                if (*nrels_mag >= 1) {
441                        data->fan_min[nr - 1] = MIN_TO_REG(results[0],
442                                                           DIV_FROM_REG
443                                                           (data->
444                                                            fan_div[nr-1]));
445                        smsc47m1_write_value(client, SMSC47M1_REG_FAN_MIN(nr),
446                                            data->fan_min[nr - 1]);
447                }
448        }
449}
450
451
452void smsc47m1_alarms(struct i2c_client *client, int operation, int ctl_name,
453                    int *nrels_mag, long *results)
454{
455        struct smsc47m1_data *data = client->data;
456        if (operation == SENSORS_PROC_REAL_INFO)
457                *nrels_mag = 0;
458        else if (operation == SENSORS_PROC_REAL_READ) {
459                smsc47m1_update_client(client);
460                results[0] = data->alarms;
461                *nrels_mag = 1;
462        }
463}
464
465void smsc47m1_fan_div(struct i2c_client *client, int operation,
466                     int ctl_name, int *nrels_mag, long *results)
467{
468        struct smsc47m1_data *data = client->data;
469        int old;
470
471        if (operation == SENSORS_PROC_REAL_INFO)
472                *nrels_mag = 0;
473        else if (operation == SENSORS_PROC_REAL_READ) {
474                smsc47m1_update_client(client);
475                results[0] = DIV_FROM_REG(data->fan_div[0]);
476                results[1] = DIV_FROM_REG(data->fan_div[1]);
477                *nrels_mag = 2;
478        } else if (operation == SENSORS_PROC_REAL_WRITE) {
479                old = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV);
480                if (*nrels_mag >= 2) {
481                        data->fan_div[1] = DIV_TO_REG(results[1]);
482                        old = (old & 0x3f) | (data->fan_div[1] << 6);
483                }
484                if (*nrels_mag >= 1) {
485                        data->fan_div[0] = DIV_TO_REG(results[0]);
486                        old = (old & 0xcf) | (data->fan_div[0] << 4);
487                        smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, old);
488                }
489        }
490}
491
492void smsc47m1_pwm(struct i2c_client *client, int operation, int ctl_name,
493                 int *nrels_mag, long *results)
494{
495        struct smsc47m1_data *data = client->data;
496        int nr = 1 + ctl_name - SMSC47M1_SYSCTL_PWM1;
497
498        if (operation == SENSORS_PROC_REAL_INFO)
499                *nrels_mag = 0;
500        else if (operation == SENSORS_PROC_REAL_READ) {
501                smsc47m1_update_client(client);
502                results[0] = PWM_FROM_REG(data->pwm[nr - 1]);
503                results[1] = data->pwm[nr - 1] >> 7;
504                *nrels_mag = 2;
505        } else if (operation == SENSORS_PROC_REAL_WRITE) {
506                if (*nrels_mag >= 1) {
507                        data->pwm[nr - 1] &= 0x80;
508                        data->pwm[nr - 1] |= PWM_TO_REG(results[0]);
509                        if (*nrels_mag >= 2) {
510                                if(results[1] && (!(data->pwm[nr-1] & 0x80))) {
511                                        /* output PWM */
512                                        smsc47m1_write_value(client,
513                                                  SMSC47M1_REG_PPIN(nr), 0x04);
514                                        data->pwm[nr - 1] |= 0x80;
515                                }
516                        }
517                        smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
518                                            data->pwm[nr - 1]);
519                }
520        }
521}
522
523int __init sensors_smsc47m1_init(void)
524{
525        int res, addr;
526
527        printk("smsc47m1.o version %s (%s)\n", LM_VERSION, LM_DATE);
528        smsc47m1_initialized = 0;
529
530        if (smsc47m1_find(&addr)) {
531                printk("smsc47m1.o: SMSC47M1xx not detected, module not inserted.\n");
532                return -ENODEV;
533        }
534        normal_isa[0] = addr;
535
536        if ((res = i2c_add_driver(&smsc47m1_driver))) {
537                printk
538                    ("smsc47m1.o: Driver registration failed, module not inserted.\n");
539                smsc47m1_cleanup();
540                return res;
541        }
542        smsc47m1_initialized++;
543        return 0;
544}
545
546int __init smsc47m1_cleanup(void)
547{
548        int res;
549
550        if (smsc47m1_initialized >= 1) {
551                if ((res = i2c_del_driver(&smsc47m1_driver))) {
552                        printk
553                            ("smsc47m1.o: Driver deregistration failed, module not removed.\n");
554                        return res;
555                }
556                smsc47m1_initialized--;
557        }
558        return 0;
559}
560
561EXPORT_NO_SYMBOLS;
562
563#ifdef MODULE
564
565MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
566MODULE_DESCRIPTION("SMSC47M110x Fan sensors");
567#ifdef MODULE_LICENSE
568MODULE_LICENSE("GPL");
569#endif
570
571int init_module(void)
572{
573        return sensors_smsc47m1_init();
574}
575
576int cleanup_module(void)
577{
578        return smsc47m1_cleanup();
579}
580
581#endif                          /* MODULE */
Note: See TracBrowser for help on using the browser.