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

Revision 4332, 17.0 KB (checked in by khali, 6 years ago)

smsc47m1: Get rid of a useless semaphore (backport from Linux 2.6).

  • 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/module.h>
23#include <linux/slab.h>
24#include <linux/ioport.h>
25#include <linux/i2c.h>
26#include <linux/i2c-proc.h>
27#include <linux/init.h>
28#include <asm/io.h>
29#include "version.h"
30
31static int force_addr = 0;
32MODULE_PARM(force_addr, "i");
33MODULE_PARM_DESC(force_addr,
34                 "Initialize the base address of the sensors");
35
36static unsigned short normal_i2c[] = { SENSORS_I2C_END };
37static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
38static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END };
39static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
40
41SENSORS_INSMOD_2(smsc47m1, smsc47m2);
42static u8 devid;
43
44/* modified from kernel/include/traps.c */
45#define REG     0x2e    /* The register to read/write */
46#define DEV     0x07    /* Register: Logical device select */
47#define VAL     0x2f    /* The value to read/write */
48#define PME     0x0a    /* The device with the fan registers in it */
49#define DEVID   0x20    /* Register: Device ID */
50
51static inline void
52superio_outb(int reg, int val)
53{
54        outb(reg, REG);
55        outb(val, VAL);
56}
57
58static inline int
59superio_inb(int reg)
60{
61        outb(reg, REG);
62        return inb(VAL);
63}
64
65static inline void
66superio_select(void)
67{
68        outb(DEV, REG);
69        outb(PME, VAL);
70}
71
72static inline void
73superio_enter(void)
74{
75        outb(0x55, REG);
76}
77
78static inline void
79superio_exit(void)
80{
81        outb(0xAA, REG);
82}
83
84/*
85 * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x
86 * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control.
87 * The 47M15x and 47M192 chips "with hardware monitoring block"
88 * can do much more besides (device id 0x60).
89 * The LPC47M997 is undocumented, but seems to be compatible with
90 * the LPC47M192, and has the same device id.
91 * The LPC47M292 (device id 0x6B) is somewhat compatible, but it
92 * supports a 3rd fan, and the pin configuration registers are
93 * unfortunately different.
94 */
95#define SMSC_DEVID_MATCH(id)    ((id) == 0x51 || (id) == 0x59 || \
96                                 (id) == 0x5F || (id) == 0x60 || \
97                                 (id) == 0x6B)
98
99#define SMSC_ACT_REG 0x30
100#define SMSC_BASE_REG 0x60
101
102#define SMSC_EXTENT 0x80
103
104#define SMSC47M1_REG_ALARM1 0x04
105#define SMSC47M1_REG_TPIN2 0x33
106#define SMSC47M1_REG_TPIN1 0x34
107#define SMSC47M1_REG_PPIN(nr) (0x37 - (nr))
108#define SMSC47M1_REG_FANDIV 0x58
109
110static const u8 SMSC47M1_REG_PWM[3] = { 0x56, 0x57, 0x69 };
111static const u8 SMSC47M1_REG_FAN[3] = { 0x59, 0x5a, 0x6b };
112static const u8 SMSC47M1_REG_FAN_MIN[3] = { 0x5b, 0x5c, 0x6c };
113
114#define SMSC47M2_REG_ALARM6 0x09
115#define SMSC47M2_REG_TPIN3 0x2d
116#define SMSC47M2_REG_TPIN2 0x37
117#define SMSC47M2_REG_TPIN1 0x38
118#define SMSC47M2_REG_FANDIV3 0x6a
119
120static inline u8 MIN_TO_REG(long rpm, int div)
121{
122        if (rpm == 0)
123                return 0;
124        rpm = SENSORS_LIMIT(rpm, 1, 1000000);
125        return SENSORS_LIMIT(192 - ((983040 + rpm * div / 2) / (rpm * div)),
126                             0, 191);
127}
128
129#define MIN_FROM_REG(val,div) ((val)>=192?0: \
130                                983040/((192-(val))*(div)))
131#define FAN_FROM_REG(val,div,preload) ((val)==0?-1:(val)==255?0: \
132                                983040/(((val)-preload)*(div)))
133#define DIV_FROM_REG(val) (1 << (val))
134#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
135/* reg is 6 middle bits; /proc is 8 bits */
136#define PWM_FROM_REG(val) (((val) << 1) & 0xfc)
137#define PWM_TO_REG(val)   (((SENSORS_LIMIT((val), 0, 255)) >> 1) & 0x7e)
138
139struct smsc47m1_data {
140        struct i2c_client client;
141        int sysctl_id;
142        enum chips type;
143
144        struct semaphore update_lock;
145        char valid;             /* !=0 if following fields are valid */
146        unsigned long last_updated;     /* In jiffies */
147
148        u8 fan[3];              /* Register value */
149        u8 fan_min[3];          /* Register value */
150        u8 fan_div[3];          /* Register encoding, shifted right */
151        u8 alarms;              /* Register encoding */
152        u8 pwm[3];              /* Register value (bit 0 is disable) */
153};
154
155
156static int smsc47m1_attach_adapter(struct i2c_adapter *adapter);
157static int smsc47m1_detect(struct i2c_adapter *adapter, int address,
158                          unsigned short flags, int kind);
159static int smsc47m1_detach_client(struct i2c_client *client);
160static void smsc47m1_update_client(struct i2c_client *client);
161static void smsc47m1_init_client(struct i2c_client *client);
162
163
164static void smsc47m1_fan(struct i2c_client *client, int operation,
165                        int ctl_name, int *nrels_mag, long *results);
166static void smsc47m1_alarms(struct i2c_client *client, int operation,
167                           int ctl_name, int *nrels_mag, long *results);
168static void smsc47m1_fan_div(struct i2c_client *client, int operation,
169                            int ctl_name, int *nrels_mag, long *results);
170static void smsc47m1_pwm(struct i2c_client *client, int operation,
171                        int ctl_name, int *nrels_mag, long *results);
172
173static struct i2c_driver smsc47m1_driver = {
174        .name           = "SMSC 47M1xx fan monitor",
175        .id             = I2C_DRIVERID_SMSC47M1,
176        .flags          = I2C_DF_NOTIFY,
177        .attach_adapter = smsc47m1_attach_adapter,
178        .detach_client  = smsc47m1_detach_client,
179};
180
181/* -- SENSORS SYSCTL START -- */
182#define SMSC47M1_SYSCTL_FAN1 1101   /* Rotations/min */
183#define SMSC47M1_SYSCTL_FAN2 1102
184#define SMSC47M1_SYSCTL_FAN3 1103
185#define SMSC47M1_SYSCTL_PWM1 1401
186#define SMSC47M1_SYSCTL_PWM2 1402
187#define SMSC47M1_SYSCTL_PWM3 1403
188#define SMSC47M1_SYSCTL_FAN_DIV 2000        /* 1, 2, 4 or 8 */
189#define SMSC47M1_SYSCTL_ALARMS 2004    /* bitvector */
190
191#define SMSC47M1_ALARM_FAN1 0x0001
192#define SMSC47M1_ALARM_FAN2 0x0002
193#define SMSC47M1_ALARM_FAN3 0x0004
194
195/* -- SENSORS SYSCTL END -- */
196
197static ctl_table smsc47m1_dir_table_template[] = {
198        {SMSC47M1_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
199         &i2c_sysctl_real, NULL, &smsc47m1_fan},
200        {SMSC47M1_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
201         &i2c_sysctl_real, NULL, &smsc47m1_fan},
202        {SMSC47M1_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
203         &i2c_sysctl_real, NULL, &smsc47m1_fan_div},
204        {SMSC47M1_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
205         &i2c_sysctl_real, NULL, &smsc47m1_alarms},
206        {SMSC47M1_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
207         &i2c_sysctl_real, NULL, &smsc47m1_pwm},
208        {SMSC47M1_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
209         &i2c_sysctl_real, NULL, &smsc47m1_pwm},
210        {0}
211};
212
213static ctl_table smsc47m2_dir_table_template[] = {
214        {SMSC47M1_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
215         &i2c_sysctl_real, NULL, &smsc47m1_fan},
216        {SMSC47M1_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
217         &i2c_sysctl_real, NULL, &smsc47m1_fan},
218        {SMSC47M1_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
219         &i2c_sysctl_real, NULL, &smsc47m1_fan},
220        {SMSC47M1_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
221         &i2c_sysctl_real, NULL, &smsc47m1_fan_div},
222        {SMSC47M1_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
223         &i2c_sysctl_real, NULL, &smsc47m1_alarms},
224        {SMSC47M1_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
225         &i2c_sysctl_real, NULL, &smsc47m1_pwm},
226        {SMSC47M1_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
227         &i2c_sysctl_real, NULL, &smsc47m1_pwm},
228        {SMSC47M1_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real,
229         &i2c_sysctl_real, NULL, &smsc47m1_pwm},
230        {0}
231};
232
233static int smsc47m1_attach_adapter(struct i2c_adapter *adapter)
234{
235        return i2c_detect(adapter, &addr_data, smsc47m1_detect);
236}
237
238static int __init smsc47m1_find(int *address)
239{
240        u16 val;
241
242        superio_enter();
243        devid = superio_inb(DEVID);
244        if (!SMSC_DEVID_MATCH(devid)) {
245                superio_exit();
246                return -ENODEV;
247        }
248
249        superio_select();
250        val = (superio_inb(SMSC_BASE_REG) << 8) |
251               superio_inb(SMSC_BASE_REG + 1);
252        *address = val & ~(SMSC_EXTENT - 1);
253        if (*address == 0 && force_addr == 0) {
254                printk("smsc47m1.o: base address not set - use force_addr=0xaddr\n");
255                superio_exit();
256                return -ENODEV;
257        }
258        if (force_addr)
259                *address = force_addr;  /* so detect will get called */
260
261        superio_exit();
262        return 0;
263}
264
265int smsc47m1_detect(struct i2c_adapter *adapter, int address,
266                   unsigned short flags, int kind)
267{
268        int i;
269        struct i2c_client *new_client;
270        struct smsc47m1_data *data;
271        int err = 0;
272        const char *type_name;
273        const char *client_name;
274
275        if (!i2c_is_isa_adapter(adapter)) {
276                return 0;
277        }
278
279        if(force_addr)
280                address = force_addr & ~(SMSC_EXTENT - 1);
281        if (check_region(address, SMSC_EXTENT)) {
282                printk("smsc47m1.o: region 0x%x already in use!\n", address);
283                return -ENODEV;
284        }
285        if(force_addr) {
286                printk("smsc47m1.o: forcing ISA address 0x%04X\n", address);
287                superio_enter();
288                superio_select();
289                superio_outb(SMSC_BASE_REG, address >> 8);
290                superio_outb(SMSC_BASE_REG+1, address & 0xff);
291                superio_exit();
292        }
293
294        if (!(data = kmalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) {
295                return -ENOMEM;
296        }
297
298        switch (devid) {
299        case 0x51:
300                kind = smsc47m1;
301                type_name = "smsc47m1";
302                client_name = "LPC47B27x chip";
303                break;
304        case 0x5F:
305                kind = smsc47m1;
306                type_name = "smsc47m1";
307                client_name = "LPC47M14x chip";
308                break;
309        case 0x60:
310                kind = smsc47m1;
311                type_name = "smsc47m1";
312                client_name = "LPC47M192 chip";
313                break;
314        case 0x6B:
315                kind = smsc47m2;
316                type_name = "smsc47m2";
317                client_name = "LPC47M292 chip";
318                break;
319        default:
320                kind = smsc47m1;
321                type_name = "smsc47m1";
322                client_name = "LPC47M1xx chip";
323        }
324
325        new_client = &data->client;
326        new_client->addr = address;
327        new_client->data = data;
328        new_client->adapter = adapter;
329        new_client->driver = &smsc47m1_driver;
330        new_client->flags = 0;
331
332        request_region(address, SMSC_EXTENT, "smsc47m1-fans");
333        strcpy(new_client->name, client_name);
334        data->type = kind;
335        data->valid = 0;
336        init_MUTEX(&data->update_lock);
337
338        if ((err = i2c_attach_client(new_client)))
339                goto ERROR3;
340
341        if ((i = i2c_register_entry((struct i2c_client *) new_client,
342                                        type_name,
343                                        kind == smsc47m2 ?
344                                                smsc47m2_dir_table_template :
345                                                smsc47m1_dir_table_template,
346                                        THIS_MODULE)) < 0) {
347                err = i;
348                goto ERROR4;
349        }
350        data->sysctl_id = i;
351
352        smsc47m1_init_client(new_client);
353        return 0;
354
355      ERROR4:
356        i2c_detach_client(new_client);
357      ERROR3:
358        release_region(address, SMSC_EXTENT);
359        kfree(data);
360        return err;
361}
362
363static int smsc47m1_detach_client(struct i2c_client *client)
364{
365        int err;
366
367        i2c_deregister_entry(((struct smsc47m1_data *) (client->data))->
368                                 sysctl_id);
369
370        if ((err = i2c_detach_client(client))) {
371                printk
372                    ("smsc47m1.o: Client deregistration failed, client not detached.\n");
373                return err;
374        }
375
376        release_region(client->addr, SMSC_EXTENT);
377        kfree(client->data);
378
379        return 0;
380}
381
382static inline int smsc47m1_read_value(struct i2c_client *client, u8 reg)
383{
384        return inb_p(client->addr + reg);
385}
386
387static inline void smsc47m1_write_value(struct i2c_client *client, u8 reg,
388                u8 value)
389{
390        outb_p(value, client->addr + reg);
391}
392
393static void smsc47m1_init_client(struct i2c_client *client)
394{
395        struct smsc47m1_data *data = client->data;
396        u8 reg;
397
398        switch (data->type) {
399        case smsc47m2:
400                /* For the new LPC47M292 chip, I prefer to play it safe and
401                   only report the pin configuration */
402                reg = smsc47m1_read_value(client, SMSC47M2_REG_TPIN1);
403                if ((reg & 0x0d) != 0x09)
404                        printk(KERN_NOTICE "smsc47m1: GP35 not configured for "
405                               "fan input, ignore fan1 values\n");
406                reg = smsc47m1_read_value(client, SMSC47M2_REG_TPIN2);
407                if ((reg & 0x0d) != 0x09)
408                        printk(KERN_NOTICE "smsc47m1: GP34 not configured for "
409                               "fan input, ignore fan2 values\n");
410                reg = smsc47m1_read_value(client, SMSC47M2_REG_TPIN3);
411                if ((reg & 0x0d) != 0x0d)
412                        printk(KERN_NOTICE "smsc47m1: GP33 not configured for "
413                               "fan input, ignore fan3 values\n");
414                break;
415        default:
416                /* configure pins for tach function */
417                smsc47m1_write_value(client, SMSC47M1_REG_TPIN1, 0x05);
418                smsc47m1_write_value(client, SMSC47M1_REG_TPIN2, 0x05);
419        }
420}
421
422static void smsc47m1_update_client(struct i2c_client *client)
423{
424        struct smsc47m1_data *data = client->data;
425
426        down(&data->update_lock);
427
428        if ((jiffies - data->last_updated > HZ + HZ / 2) ||
429            (jiffies < data->last_updated) || !data->valid) {
430                int i, fan_nr;
431                fan_nr = data->type == smsc47m2 ? 3 : 2;
432
433                for (i = 0; i < fan_nr; i++) {
434                        data->fan[i] =
435                            smsc47m1_read_value(client, SMSC47M1_REG_FAN[i]);
436                        data->fan_min[i] =
437                            smsc47m1_read_value(client, SMSC47M1_REG_FAN_MIN[i]);
438                        data->pwm[i] =
439                            smsc47m1_read_value(client, SMSC47M1_REG_PWM[i]);
440                }
441
442                i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV);
443                data->fan_div[0] = (i >> 4) & 0x03;
444                data->fan_div[1] = i >> 6;
445                data->alarms =
446                        smsc47m1_read_value(client, SMSC47M1_REG_ALARM1) >> 6;
447                if(data->alarms)
448                        smsc47m1_write_value(client, SMSC47M1_REG_ALARM1, 0xc0);
449
450                if (fan_nr >= 3) {
451                        data->fan_div[2] = (smsc47m1_read_value(client,
452                                            SMSC47M2_REG_FANDIV3) >> 4) & 0x03;
453                        data->alarms |= (smsc47m1_read_value(client,
454                                         SMSC47M2_REG_ALARM6) & 0x40) >> 4;
455                        if (data->alarms & 0x04)
456                                smsc47m1_write_value(client,
457                                                     SMSC47M2_REG_ALARM6,
458                                                     0x40);
459                }
460
461                data->last_updated = jiffies;
462                data->valid = 1;
463        }
464
465        up(&data->update_lock);
466}
467
468
469void smsc47m1_fan(struct i2c_client *client, int operation, int ctl_name,
470                 int *nrels_mag, long *results)
471{
472        struct smsc47m1_data *data = client->data;
473        int nr = ctl_name - SMSC47M1_SYSCTL_FAN1;
474
475        if (operation == SENSORS_PROC_REAL_INFO)
476                *nrels_mag = 0;
477        else if (operation == SENSORS_PROC_REAL_READ) {
478                smsc47m1_update_client(client);
479                results[0] = MIN_FROM_REG(data->fan_min[nr],
480                                          DIV_FROM_REG(data->fan_div[nr]));
481                results[1] = FAN_FROM_REG(data->fan[nr],
482                                          DIV_FROM_REG(data->fan_div[nr]),
483                                          data->fan_min[nr]);
484                *nrels_mag = 2;
485        } else if (operation == SENSORS_PROC_REAL_WRITE) {
486                if (*nrels_mag >= 1) {
487                        data->fan_min[nr] = MIN_TO_REG(results[0],
488                                            DIV_FROM_REG(data->fan_div[nr]));
489                        smsc47m1_write_value(client, SMSC47M1_REG_FAN_MIN[nr],
490                                            data->fan_min[nr]);
491                }
492        }
493}
494
495
496void smsc47m1_alarms(struct i2c_client *client, int operation, int ctl_name,
497                    int *nrels_mag, long *results)
498{
499        struct smsc47m1_data *data = client->data;
500        if (operation == SENSORS_PROC_REAL_INFO)
501                *nrels_mag = 0;
502        else if (operation == SENSORS_PROC_REAL_READ) {
503                smsc47m1_update_client(client);
504                results[0] = data->alarms;
505                *nrels_mag = 1;
506        }
507}
508
509void smsc47m1_fan_div(struct i2c_client *client, int operation,
510                     int ctl_name, int *nrels_mag, long *results)
511{
512        struct smsc47m1_data *data = client->data;
513        int old;
514
515        if (operation == SENSORS_PROC_REAL_INFO)
516                *nrels_mag = 0;
517        else if (operation == SENSORS_PROC_REAL_READ) {
518                smsc47m1_update_client(client);
519                results[0] = DIV_FROM_REG(data->fan_div[0]);
520                results[1] = DIV_FROM_REG(data->fan_div[1]);
521                *nrels_mag = 2;
522        } else if (operation == SENSORS_PROC_REAL_WRITE) {
523                old = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV);
524                if (*nrels_mag >= 3 && data->type == smsc47m2) {
525                        data->fan_div[2] = DIV_TO_REG(results[2]);
526                        smsc47m1_write_value(client, SMSC47M2_REG_FANDIV3,
527                                (smsc47m1_read_value(client,
528                                 SMSC47M2_REG_FANDIV3) & 0xcf)
529                                | (data->fan_div[2] << 4));
530                }
531                if (*nrels_mag >= 2) {
532                        data->fan_div[1] = DIV_TO_REG(results[1]);
533                        old = (old & 0x3f) | (data->fan_div[1] << 6);
534                }
535                if (*nrels_mag >= 1) {
536                        data->fan_div[0] = DIV_TO_REG(results[0]);
537                        old = (old & 0xcf) | (data->fan_div[0] << 4);
538                        smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, old);
539                }
540        }
541}
542
543void smsc47m1_pwm(struct i2c_client *client, int operation, int ctl_name,
544                 int *nrels_mag, long *results)
545{
546        struct smsc47m1_data *data = client->data;
547        int nr = ctl_name - SMSC47M1_SYSCTL_PWM1;
548
549        if (operation == SENSORS_PROC_REAL_INFO)
550                *nrels_mag = 0;
551        else if (operation == SENSORS_PROC_REAL_READ) {
552                smsc47m1_update_client(client);
553                results[0] = PWM_FROM_REG(data->pwm[nr]);
554                results[1] = !(data->pwm[nr] & 0x01);
555                *nrels_mag = 2;
556        } else if (operation == SENSORS_PROC_REAL_WRITE) {
557                if (*nrels_mag >= 1) {
558                        data->pwm[nr] = smsc47m1_read_value(client,
559                                            SMSC47M1_REG_PWM[nr]) & 0x81;
560                        data->pwm[nr] |= PWM_TO_REG(results[0]);
561                        if (*nrels_mag >= 2) {
562                                if (results[1]) {
563                                        /* enable PWM */
564                                        data->pwm[nr] &= 0xfe;
565                                } else {
566                                        /* disable PWM */
567                                        data->pwm[nr] |= 0x01;
568                                }
569                        }
570                        smsc47m1_write_value(client, SMSC47M1_REG_PWM[nr],
571                                             data->pwm[nr]);
572                }
573        }
574}
575
576static int __init sm_smsc47m1_init(void)
577{
578        int addr;
579
580        printk("smsc47m1.o version %s (%s)\n", LM_VERSION, LM_DATE);
581
582        if (smsc47m1_find(&addr)) {
583                printk("smsc47m1.o: SMSC 47M1xx not detected, module not inserted.\n");
584                return -ENODEV;
585        }
586        normal_isa[0] = addr;
587
588        return i2c_add_driver(&smsc47m1_driver);
589}
590
591static void __exit sm_smsc47m1_exit(void)
592{
593        i2c_del_driver(&smsc47m1_driver);
594}
595
596
597
598MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
599MODULE_DESCRIPTION("SMSC 47M1xx Fan sensors");
600MODULE_LICENSE("GPL");
601
602module_init(sm_smsc47m1_init);
603module_exit(sm_smsc47m1_exit);
Note: See TracBrowser for help on using the browser.