2 smsc47m1.c - Part of lm_sensors, Linux kernel modules
3 for hardware monitoring
5 Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x,
6 LPC47M14x, LPC47M15x, LPC47M192, LPC47M292 and LPC47M997
9 Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
10 Copyright (C) 2004-2007 Jean Delvare <khali@linux-fr.org>
11 Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com>
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <linux/module.h>
30 #include <linux/slab.h>
31 #include <linux/ioport.h>
32 #include <linux/jiffies.h>
33 #include <linux/platform_device.h>
34 #include <linux/hwmon.h>
35 #include <linux/hwmon-sysfs.h>
36 #include <linux/err.h>
37 #include <linux/init.h>
38 #include <linux/mutex.h>
39 #include <linux/sysfs.h>
42 static struct platform_device *pdev;
44 #define DRVNAME "smsc47m1"
45 enum chips { smsc47m1, smsc47m2 };
47 /* Super-I/0 registers and commands */
49 #define REG 0x2e /* The register to read/write */
50 #define VAL 0x2f /* The value to read/write */
53 superio_outb(int reg, int val)
66 /* logical device for fans is 0x0A */
67 #define superio_select() superio_outb(0x07, 0x0A)
81 #define SUPERIO_REG_ACT 0x30
82 #define SUPERIO_REG_BASE 0x60
83 #define SUPERIO_REG_DEVID 0x20
85 /* Logical device registers */
87 #define SMSC_EXTENT 0x80
89 /* nr is 0 or 1 in the macros below */
90 #define SMSC47M1_REG_ALARM 0x04
91 #define SMSC47M1_REG_TPIN(nr) (0x34 - (nr))
92 #define SMSC47M1_REG_PPIN(nr) (0x36 - (nr))
93 #define SMSC47M1_REG_FANDIV 0x58
95 static const u8 SMSC47M1_REG_FAN[3] = { 0x59, 0x5a, 0x6b };
96 static const u8 SMSC47M1_REG_FAN_PRELOAD[3] = { 0x5b, 0x5c, 0x6c };
97 static const u8 SMSC47M1_REG_PWM[3] = { 0x56, 0x57, 0x69 };
99 #define SMSC47M2_REG_ALARM6 0x09
100 #define SMSC47M2_REG_TPIN1 0x38
101 #define SMSC47M2_REG_TPIN2 0x37
102 #define SMSC47M2_REG_TPIN3 0x2d
103 #define SMSC47M2_REG_PPIN3 0x2c
104 #define SMSC47M2_REG_FANDIV3 0x6a
106 #define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \
107 983040/((192-(reg))*(div)))
108 #define FAN_FROM_REG(reg,div,preload) ((reg)<=(preload) || (reg)==255 ? 0 : \
109 983040/(((reg)-(preload))*(div)))
110 #define DIV_FROM_REG(reg) (1 << (reg))
111 #define PWM_FROM_REG(reg) (((reg) & 0x7E) << 1)
112 #define PWM_EN_FROM_REG(reg) ((~(reg)) & 0x01)
113 #define PWM_TO_REG(reg) (((reg) >> 1) & 0x7E)
115 struct smsc47m1_data {
119 struct class_device *class_dev;
121 struct mutex update_lock;
122 unsigned long last_updated; /* In jiffies */
124 u8 fan[3]; /* Register value */
125 u8 fan_preload[3]; /* Register value */
126 u8 fan_div[3]; /* Register encoding, shifted right */
127 u8 alarms; /* Register encoding */
128 u8 pwm[3]; /* Register value (bit 0 is disable) */
131 struct smsc47m1_sio_data {
136 static int smsc47m1_probe(struct platform_device *pdev);
137 static int smsc47m1_remove(struct platform_device *pdev);
138 static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
141 static inline int smsc47m1_read_value(struct smsc47m1_data *data, u8 reg)
143 return inb_p(data->addr + reg);
146 static inline void smsc47m1_write_value(struct smsc47m1_data *data, u8 reg,
149 outb_p(value, data->addr + reg);
152 static struct platform_driver smsc47m1_driver = {
154 .owner = THIS_MODULE,
157 .probe = smsc47m1_probe,
158 .remove = __devexit_p(smsc47m1_remove),
161 static ssize_t get_fan(struct device *dev, struct device_attribute
164 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
165 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
166 int nr = attr->index;
167 /* This chip (stupidly) stops monitoring fan speed if PWM is
168 enabled and duty cycle is 0%. This is fine if the monitoring
169 and control concern the same fan, but troublesome if they are
170 not (which could as well happen). */
171 int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 :
172 FAN_FROM_REG(data->fan[nr],
173 DIV_FROM_REG(data->fan_div[nr]),
174 data->fan_preload[nr]);
175 return sprintf(buf, "%d\n", rpm);
178 static ssize_t get_fan_min(struct device *dev, struct device_attribute
181 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
182 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
183 int nr = attr->index;
184 int rpm = MIN_FROM_REG(data->fan_preload[nr],
185 DIV_FROM_REG(data->fan_div[nr]));
186 return sprintf(buf, "%d\n", rpm);
189 static ssize_t get_fan_div(struct device *dev, struct device_attribute
192 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
193 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
194 return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
197 static ssize_t get_pwm(struct device *dev, struct device_attribute
200 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
201 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
202 return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[attr->index]));
205 static ssize_t get_pwm_en(struct device *dev, struct device_attribute
208 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
209 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
210 return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[attr->index]));
213 static ssize_t get_alarms(struct device *dev, struct device_attribute
216 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
217 return sprintf(buf, "%d\n", data->alarms);
220 static ssize_t set_fan_min(struct device *dev, struct device_attribute
221 *devattr, const char *buf, size_t count)
223 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
224 struct smsc47m1_data *data = dev_get_drvdata(dev);
225 int nr = attr->index;
226 long rpmdiv, val = simple_strtol(buf, NULL, 10);
228 mutex_lock(&data->update_lock);
229 rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]);
231 if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) {
232 mutex_unlock(&data->update_lock);
236 data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv);
237 smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
238 data->fan_preload[nr]);
239 mutex_unlock(&data->update_lock);
244 /* Note: we save and restore the fan minimum here, because its value is
245 determined in part by the fan clock divider. This follows the principle
246 of least surprise; the user doesn't expect the fan minimum to change just
247 because the divider changed. */
248 static ssize_t set_fan_div(struct device *dev, struct device_attribute
249 *devattr, const char *buf, size_t count)
251 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
252 struct smsc47m1_data *data = dev_get_drvdata(dev);
253 int nr = attr->index;
254 long new_div = simple_strtol(buf, NULL, 10), tmp;
255 u8 old_div = DIV_FROM_REG(data->fan_div[nr]);
257 if (new_div == old_div) /* No change */
260 mutex_lock(&data->update_lock);
262 case 1: data->fan_div[nr] = 0; break;
263 case 2: data->fan_div[nr] = 1; break;
264 case 4: data->fan_div[nr] = 2; break;
265 case 8: data->fan_div[nr] = 3; break;
267 mutex_unlock(&data->update_lock);
274 tmp = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV)
275 & ~(0x03 << (4 + 2 * nr));
276 tmp |= data->fan_div[nr] << (4 + 2 * nr);
277 smsc47m1_write_value(data, SMSC47M1_REG_FANDIV, tmp);
280 tmp = smsc47m1_read_value(data, SMSC47M2_REG_FANDIV3) & 0xCF;
281 tmp |= data->fan_div[2] << 4;
282 smsc47m1_write_value(data, SMSC47M2_REG_FANDIV3, tmp);
286 /* Preserve fan min */
287 tmp = 192 - (old_div * (192 - data->fan_preload[nr])
288 + new_div / 2) / new_div;
289 data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191);
290 smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
291 data->fan_preload[nr]);
292 mutex_unlock(&data->update_lock);
297 static ssize_t set_pwm(struct device *dev, struct device_attribute
298 *devattr, const char *buf, size_t count)
300 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
301 struct smsc47m1_data *data = dev_get_drvdata(dev);
302 int nr = attr->index;
303 long val = simple_strtol(buf, NULL, 10);
305 if (val < 0 || val > 255)
308 mutex_lock(&data->update_lock);
309 data->pwm[nr] &= 0x81; /* Preserve additional bits */
310 data->pwm[nr] |= PWM_TO_REG(val);
311 smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
313 mutex_unlock(&data->update_lock);
318 static ssize_t set_pwm_en(struct device *dev, struct device_attribute
319 *devattr, const char *buf, size_t count)
321 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
322 struct smsc47m1_data *data = dev_get_drvdata(dev);
323 int nr = attr->index;
324 long val = simple_strtol(buf, NULL, 10);
326 if (val != 0 && val != 1)
329 mutex_lock(&data->update_lock);
330 data->pwm[nr] &= 0xFE; /* preserve the other bits */
331 data->pwm[nr] |= !val;
332 smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
334 mutex_unlock(&data->update_lock);
339 #define fan_present(offset) \
340 static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan, \
342 static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
343 get_fan_min, set_fan_min, offset - 1); \
344 static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
345 get_fan_div, set_fan_div, offset - 1); \
346 static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
347 get_pwm, set_pwm, offset - 1); \
348 static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
349 get_pwm_en, set_pwm_en, offset - 1)
355 static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
357 static ssize_t show_name(struct device *dev, struct device_attribute
360 struct smsc47m1_data *data = dev_get_drvdata(dev);
362 return sprintf(buf, "%s\n", data->name);
364 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
366 /* Almost all sysfs files may or may not be created depending on the chip
367 setup so we create them individually. It is still convenient to define a
368 group to remove them all at once. */
369 static struct attribute *smsc47m1_attributes[] = {
370 &sensor_dev_attr_fan1_input.dev_attr.attr,
371 &sensor_dev_attr_fan1_min.dev_attr.attr,
372 &sensor_dev_attr_fan1_div.dev_attr.attr,
373 &sensor_dev_attr_fan2_input.dev_attr.attr,
374 &sensor_dev_attr_fan2_min.dev_attr.attr,
375 &sensor_dev_attr_fan2_div.dev_attr.attr,
376 &sensor_dev_attr_fan3_input.dev_attr.attr,
377 &sensor_dev_attr_fan3_min.dev_attr.attr,
378 &sensor_dev_attr_fan3_div.dev_attr.attr,
380 &sensor_dev_attr_pwm1.dev_attr.attr,
381 &sensor_dev_attr_pwm1_enable.dev_attr.attr,
382 &sensor_dev_attr_pwm2.dev_attr.attr,
383 &sensor_dev_attr_pwm2_enable.dev_attr.attr,
384 &sensor_dev_attr_pwm3.dev_attr.attr,
385 &sensor_dev_attr_pwm3_enable.dev_attr.attr,
387 &dev_attr_alarms.attr,
392 static const struct attribute_group smsc47m1_group = {
393 .attrs = smsc47m1_attributes,
396 static int __init smsc47m1_find(unsigned short *addr,
397 struct smsc47m1_sio_data *sio_data)
402 val = superio_inb(SUPERIO_REG_DEVID);
405 * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x
406 * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control.
407 * The LPC47M15x and LPC47M192 chips "with hardware monitoring block"
408 * can do much more besides (device id 0x60).
409 * The LPC47M997 is undocumented, but seems to be compatible with
410 * the LPC47M192, and has the same device id.
411 * The LPC47M292 (device id 0x6B) is somewhat compatible, but it
412 * supports a 3rd fan, and the pin configuration registers are
413 * unfortunately different.
417 pr_info(DRVNAME ": Found SMSC LPC47B27x\n");
418 sio_data->type = smsc47m1;
421 pr_info(DRVNAME ": Found SMSC LPC47M10x/LPC47M112/LPC47M13x\n");
422 sio_data->type = smsc47m1;
425 pr_info(DRVNAME ": Found SMSC LPC47M14x\n");
426 sio_data->type = smsc47m1;
429 pr_info(DRVNAME ": Found SMSC LPC47M15x/LPC47M192/LPC47M997\n");
430 sio_data->type = smsc47m1;
433 pr_info(DRVNAME ": Found SMSC LPC47M292\n");
434 sio_data->type = smsc47m2;
442 *addr = (superio_inb(SUPERIO_REG_BASE) << 8)
443 | superio_inb(SUPERIO_REG_BASE + 1);
444 val = superio_inb(SUPERIO_REG_ACT);
445 if (*addr == 0 || (val & 0x01) == 0) {
446 pr_info(DRVNAME ": Device is disabled, will not use\n");
455 static int __devinit smsc47m1_probe(struct platform_device *pdev)
457 struct device *dev = &pdev->dev;
458 struct smsc47m1_sio_data *sio_data = dev->platform_data;
459 struct smsc47m1_data *data;
460 struct resource *res;
462 int fan1, fan2, fan3, pwm1, pwm2, pwm3;
464 static const char *names[] = {
469 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
470 if (!request_region(res->start, SMSC_EXTENT, DRVNAME)) {
471 dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
472 (unsigned long)res->start,
473 (unsigned long)res->end);
477 if (!(data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) {
482 data->addr = res->start;
483 data->type = sio_data->type;
484 data->name = names[sio_data->type];
485 mutex_init(&data->update_lock);
486 platform_set_drvdata(pdev, data);
488 /* If no function is properly configured, there's no point in
489 actually registering the chip. */
490 pwm1 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(0)) & 0x05)
492 pwm2 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(1)) & 0x05)
494 if (data->type == smsc47m2) {
495 fan1 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN1)
497 fan2 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN2)
499 fan3 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN3)
501 pwm3 = (smsc47m1_read_value(data, SMSC47M2_REG_PPIN3)
504 fan1 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(0))
506 fan2 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(1))
511 if (!(fan1 || fan2 || fan3 || pwm1 || pwm2 || pwm3)) {
512 dev_warn(dev, "Device not configured, will not use\n");
517 /* Some values (fan min, clock dividers, pwm registers) may be
518 needed before any update is triggered, so we better read them
519 at least once here. We don't usually do it that way, but in
520 this particular case, manually reading 5 registers out of 8
521 doesn't make much sense and we're better using the existing
523 smsc47m1_update_device(dev, 1);
525 /* Register sysfs hooks */
527 if ((err = device_create_file(dev,
528 &sensor_dev_attr_fan1_input.dev_attr))
529 || (err = device_create_file(dev,
530 &sensor_dev_attr_fan1_min.dev_attr))
531 || (err = device_create_file(dev,
532 &sensor_dev_attr_fan1_div.dev_attr)))
533 goto error_remove_files;
535 dev_dbg(dev, "Fan 1 not enabled by hardware, skipping\n");
538 if ((err = device_create_file(dev,
539 &sensor_dev_attr_fan2_input.dev_attr))
540 || (err = device_create_file(dev,
541 &sensor_dev_attr_fan2_min.dev_attr))
542 || (err = device_create_file(dev,
543 &sensor_dev_attr_fan2_div.dev_attr)))
544 goto error_remove_files;
546 dev_dbg(dev, "Fan 2 not enabled by hardware, skipping\n");
549 if ((err = device_create_file(dev,
550 &sensor_dev_attr_fan3_input.dev_attr))
551 || (err = device_create_file(dev,
552 &sensor_dev_attr_fan3_min.dev_attr))
553 || (err = device_create_file(dev,
554 &sensor_dev_attr_fan3_div.dev_attr)))
555 goto error_remove_files;
557 dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n");
560 if ((err = device_create_file(dev,
561 &sensor_dev_attr_pwm1.dev_attr))
562 || (err = device_create_file(dev,
563 &sensor_dev_attr_pwm1_enable.dev_attr)))
564 goto error_remove_files;
566 dev_dbg(dev, "PWM 1 not enabled by hardware, skipping\n");
569 if ((err = device_create_file(dev,
570 &sensor_dev_attr_pwm2.dev_attr))
571 || (err = device_create_file(dev,
572 &sensor_dev_attr_pwm2_enable.dev_attr)))
573 goto error_remove_files;
575 dev_dbg(dev, "PWM 2 not enabled by hardware, skipping\n");
578 if ((err = device_create_file(dev,
579 &sensor_dev_attr_pwm3.dev_attr))
580 || (err = device_create_file(dev,
581 &sensor_dev_attr_pwm3_enable.dev_attr)))
582 goto error_remove_files;
584 dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n");
586 if ((err = device_create_file(dev, &dev_attr_alarms)))
587 goto error_remove_files;
589 data->class_dev = hwmon_device_register(dev);
590 if (IS_ERR(data->class_dev)) {
591 err = PTR_ERR(data->class_dev);
592 goto error_remove_files;
598 sysfs_remove_group(&dev->kobj, &smsc47m1_group);
602 release_region(res->start, SMSC_EXTENT);
606 static int __devexit smsc47m1_remove(struct platform_device *pdev)
608 struct smsc47m1_data *data = platform_get_drvdata(pdev);
609 struct resource *res;
611 platform_set_drvdata(pdev, NULL);
612 hwmon_device_unregister(data->class_dev);
613 sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
615 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
616 release_region(res->start, SMSC_EXTENT);
622 static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
625 struct smsc47m1_data *data = dev_get_drvdata(dev);
627 mutex_lock(&data->update_lock);
629 if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) {
631 fan_nr = data->type == smsc47m2 ? 3 : 2;
633 for (i = 0; i < fan_nr; i++) {
634 data->fan[i] = smsc47m1_read_value(data,
635 SMSC47M1_REG_FAN[i]);
636 data->fan_preload[i] = smsc47m1_read_value(data,
637 SMSC47M1_REG_FAN_PRELOAD[i]);
638 data->pwm[i] = smsc47m1_read_value(data,
639 SMSC47M1_REG_PWM[i]);
642 i = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV);
643 data->fan_div[0] = (i >> 4) & 0x03;
644 data->fan_div[1] = i >> 6;
646 data->alarms = smsc47m1_read_value(data,
647 SMSC47M1_REG_ALARM) >> 6;
648 /* Clear alarms if needed */
650 smsc47m1_write_value(data, SMSC47M1_REG_ALARM, 0xC0);
653 data->fan_div[2] = (smsc47m1_read_value(data,
654 SMSC47M2_REG_FANDIV3) >> 4) & 0x03;
655 data->alarms |= (smsc47m1_read_value(data,
656 SMSC47M2_REG_ALARM6) & 0x40) >> 4;
657 /* Clear alarm if needed */
658 if (data->alarms & 0x04)
659 smsc47m1_write_value(data,
664 data->last_updated = jiffies;
667 mutex_unlock(&data->update_lock);
671 static int __init smsc47m1_device_add(unsigned short address,
672 const struct smsc47m1_sio_data *sio_data)
674 struct resource res = {
676 .end = address + SMSC_EXTENT - 1,
678 .flags = IORESOURCE_IO,
682 pdev = platform_device_alloc(DRVNAME, address);
685 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
689 err = platform_device_add_resources(pdev, &res, 1);
691 printk(KERN_ERR DRVNAME ": Device resource addition failed "
693 goto exit_device_put;
696 pdev->dev.platform_data = kmalloc(sizeof(struct smsc47m1_sio_data),
698 if (!pdev->dev.platform_data) {
700 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
701 goto exit_device_put;
703 memcpy(pdev->dev.platform_data, sio_data,
704 sizeof(struct smsc47m1_sio_data));
706 err = platform_device_add(pdev);
708 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
710 goto exit_device_put;
716 platform_device_put(pdev);
721 static int __init sm_smsc47m1_init(void)
724 unsigned short address;
725 struct smsc47m1_sio_data sio_data;
727 if (smsc47m1_find(&address, &sio_data))
730 err = platform_driver_register(&smsc47m1_driver);
734 /* Sets global pdev as a side effect */
735 err = smsc47m1_device_add(address, &sio_data);
742 platform_driver_unregister(&smsc47m1_driver);
747 static void __exit sm_smsc47m1_exit(void)
749 platform_device_unregister(pdev);
750 platform_driver_unregister(&smsc47m1_driver);
753 MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
754 MODULE_DESCRIPTION("SMSC LPC47M1xx fan sensors driver");
755 MODULE_LICENSE("GPL");
757 module_init(sm_smsc47m1_init);
758 module_exit(sm_smsc47m1_exit);