#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/ioport.h>
#include <asm/io.h>
static int uch_config = -1;
module_param(int_mode, int, 0);
MODULE_PARM_DESC(int_mode, "Force the temperature interrupt mode");
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
static struct platform_device *pdev;
#define DRVNAME "vt1211"
struct vt1211_data {
unsigned short addr;
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
* Super-I/O constants and functions
* --------------------------------------------------------------------- */
-/* Configuration & data index port registers */
-#define SIO_REG_CIP 0x2e
-#define SIO_REG_DIP 0x2f
+/* Configuration index port registers
+ * The vt1211 can live at 2 different addresses so we need to probe both */
+#define SIO_REG_CIP1 0x2e
+#define SIO_REG_CIP2 0x4e
/* Configuration registers */
#define SIO_VT1211_LDN 0x07 /* logical device number */
/* VT1211 logical device numbers */
#define SIO_VT1211_LDN_HWMON 0x0b /* HW monitor */
-static inline void superio_outb(int reg, int val)
+static inline void superio_outb(int sio_cip, int reg, int val)
{
- outb(reg, SIO_REG_CIP);
- outb(val, SIO_REG_DIP);
+ outb(reg, sio_cip);
+ outb(val, sio_cip + 1);
}
-static inline int superio_inb(int reg)
+static inline int superio_inb(int sio_cip, int reg)
{
- outb(reg, SIO_REG_CIP);
- return inb(SIO_REG_DIP);
+ outb(reg, sio_cip);
+ return inb(sio_cip + 1);
}
-static inline void superio_select(int ldn)
+static inline void superio_select(int sio_cip, int ldn)
{
- outb(SIO_VT1211_LDN, SIO_REG_CIP);
- outb(ldn, SIO_REG_DIP);
+ outb(SIO_VT1211_LDN, sio_cip);
+ outb(ldn, sio_cip + 1);
}
-static inline void superio_enter(void)
+static inline void superio_enter(int sio_cip)
{
- outb(0x87, SIO_REG_CIP);
- outb(0x87, SIO_REG_CIP);
+ outb(0x87, sio_cip);
+ outb(0x87, sio_cip);
}
-static inline void superio_exit(void)
+static inline void superio_exit(int sio_cip)
{
- outb(0xaa, SIO_REG_CIP);
+ outb(0xaa, sio_cip);
}
/* ---------------------------------------------------------------------
if ((val < 0) || (val > 255)) {
dev_err(dev, "pwm value %ld is out of range. "
- "Choose a value between 0 and 255." , val);
+ "Choose a value between 0 and 255.\n" , val);
return -EINVAL;
}
}
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) {
+ err = -EBUSY;
+ dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+ (unsigned long)res->start, (unsigned long)res->end);
+ goto EXIT_KFREE;
+ }
data->addr = res->start;
data->name = DRVNAME;
mutex_init(&data->update_lock);
}
/* Register device */
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
dev_err(dev, "Class registration failed (%d)\n", err);
goto EXIT_DEV_REMOVE_SILENT;
}
dev_err(dev, "Sysfs interface creation failed (%d)\n", err);
EXIT_DEV_REMOVE_SILENT:
vt1211_remove_sysfs(pdev);
+ release_region(res->start, res->end - res->start + 1);
+EXIT_KFREE:
platform_set_drvdata(pdev, NULL);
kfree(data);
EXIT:
static int __devexit vt1211_remove(struct platform_device *pdev)
{
struct vt1211_data *data = platform_get_drvdata(pdev);
+ struct resource *res;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
vt1211_remove_sysfs(pdev);
platform_set_drvdata(pdev, NULL);
kfree(data);
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(res->start, res->end - res->start + 1);
+
return 0;
}
return err;
}
-static int __init vt1211_find(unsigned short *address)
+static int __init vt1211_find(int sio_cip, unsigned short *address)
{
int err = -ENODEV;
+ int devid;
- superio_enter();
+ superio_enter(sio_cip);
- if (superio_inb(SIO_VT1211_DEVID) != SIO_VT1211_ID) {
+ devid = force_id ? force_id : superio_inb(sio_cip, SIO_VT1211_DEVID);
+ if (devid != SIO_VT1211_ID) {
goto EXIT;
}
- superio_select(SIO_VT1211_LDN_HWMON);
+ superio_select(sio_cip, SIO_VT1211_LDN_HWMON);
- if ((superio_inb(SIO_VT1211_ACTIVE) & 1) == 0) {
+ if ((superio_inb(sio_cip, SIO_VT1211_ACTIVE) & 1) == 0) {
printk(KERN_WARNING DRVNAME ": HW monitor is disabled, "
"skipping\n");
goto EXIT;
}
- *address = ((superio_inb(SIO_VT1211_BADDR) << 8) |
- (superio_inb(SIO_VT1211_BADDR + 1))) & 0xff00;
+ *address = ((superio_inb(sio_cip, SIO_VT1211_BADDR) << 8) |
+ (superio_inb(sio_cip, SIO_VT1211_BADDR + 1))) & 0xff00;
if (*address == 0) {
printk(KERN_WARNING DRVNAME ": Base address is not set, "
"skipping\n");
err = 0;
printk(KERN_INFO DRVNAME ": Found VT1211 chip at 0x%04x, "
- "revision %u\n", *address, superio_inb(SIO_VT1211_DEVREV));
+ "revision %u\n", *address,
+ superio_inb(sio_cip, SIO_VT1211_DEVREV));
EXIT:
- superio_exit();
+ superio_exit(sio_cip);
return err;
}
int err;
unsigned short address = 0;
- err = vt1211_find(&address);
- if (err) {
+ if ((err = vt1211_find(SIO_REG_CIP1, &address)) &&
+ (err = vt1211_find(SIO_REG_CIP2, &address))) {
goto EXIT;
}