* [lm-sensors] [PATCH 1/2] hwmon: w83781d: make ISA interface depend
@ 2008-09-13 8:53 Wolfgang Grandegger
2008-10-06 13:13 ` [lm-sensors] [PATCH 1/2] hwmon: w83781d: make ISA interface Jean Delvare
2008-10-06 13:32 ` Wolfgang Grandegger
0 siblings, 2 replies; 3+ messages in thread
From: Wolfgang Grandegger @ 2008-09-13 8:53 UTC (permalink / raw)
To: lm-sensors
Probing the ISA bus on systems without ISA bus may hang the system.
This patch makes the ISA bus related code depend on the kernel
configuration parameter CONFIG_ISA. It moves ISA bus related code
into one #ifdef CONFIG_ISA ... #endif block and adds some helper
function.
Note that this patch is based on the patches:
hwmon-w83781d-01-refactor-beep-enable.patch
hwmon-w83781d-02-alias-detect.patch
from http://jdelvare.pck.nerim.net/sensors/w83781d/.
Signed-off-by: Wolfgang Grandegger <wg@grandegger.com>
---
drivers/hwmon/w83781d.c | 666 +++++++++++++++++++++++++++---------------------
1 file changed, 388 insertions(+), 278 deletions(-)
Index: linux-2.6-denx/drivers/hwmon/w83781d.c
=================================--- linux-2.6-denx.orig/drivers/hwmon/w83781d.c
+++ linux-2.6-denx/drivers/hwmon/w83781d.c
@@ -49,14 +49,9 @@
#include <asm/io.h>
#include "lm75.h"
-/* ISA device, if found */
-static struct platform_device *pdev;
-
/* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f, I2C_CLIENT_END };
-static unsigned short isa_address = 0x290;
-
/* Insmod parameters */
I2C_CLIENT_INSMOD_4(w83781d, w83782d, w83783s, as99127f);
I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
@@ -245,13 +240,13 @@ struct w83781d_data {
u8 vrm;
};
+static struct w83781d_data *w83781d_data_if_isa(void);
+static int w83781d_alias_detect(struct i2c_client *client, u8 chipid);
+
static int w83781d_attach_adapter(struct i2c_adapter *adapter);
static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind);
static int w83781d_detach_client(struct i2c_client *client);
-static int __devinit w83781d_isa_probe(struct platform_device *pdev);
-static int __devexit w83781d_isa_remove(struct platform_device *pdev);
-
static int w83781d_read_value(struct w83781d_data *data, u16 reg);
static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);
static struct w83781d_data *w83781d_update_device(struct device *dev);
@@ -265,16 +260,6 @@ static struct i2c_driver w83781d_driver
.detach_client = w83781d_detach_client,
};
-static struct platform_driver w83781d_isa_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "w83781d",
- },
- .probe = w83781d_isa_probe,
- .remove = w83781d_isa_remove,
-};
-
-
/* following are the sysfs callback functions */
#define show_in_reg(reg) \
static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
@@ -836,16 +821,6 @@ static SENSOR_DEVICE_ATTR(temp2_type, S_
static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
show_sensor, store_sensor, 2);
-/* I2C devices get this name attribute automatically, but for ISA devices
- we must create it by ourselves. */
-static ssize_t
-show_name(struct device *dev, struct device_attribute *devattr, char *buf)
-{
- struct w83781d_data *data = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", data->client.name);
-}
-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-
/* This function is called when:
* w83781d_driver is inserted (when this module is loaded), for each
available adapter
@@ -855,13 +830,12 @@ static DEVICE_ATTR(name, S_IRUGO, show_n
static int
w83781d_attach_adapter(struct i2c_adapter *adapter)
{
- struct w83781d_data *data;
+ struct w83781d_data *data = w83781d_data_if_isa();
int err;
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- data = pdev ? platform_get_drvdata(pdev) : NULL;
if (data)
mutex_lock(&data->update_lock);
err = i2c_probe(adapter, &addr_data, w83781d_detect);
@@ -1037,40 +1011,6 @@ static const struct attribute_group w837
.attrs = w83781d_attributes_opt,
};
-/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
-static int w83781d_alias_detect(struct i2c_client *client, u8 chipid)
-{
- struct w83781d_data *i2c, *isa;
- int i;
-
- if (!pdev) /* No ISA chip */
- return 0;
-
- i2c = i2c_get_clientdata(client);
- isa = platform_get_drvdata(pdev);
-
- if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr)
- return 0; /* Address doesn't match */
- if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid)
- return 0; /* Chip type doesn't match */
-
- /* We compare all the limit registers, the config register and the
- * interrupt mask registers */
- for (i = 0x2b; i <= 0x3d; i++) {
- if (w83781d_read_value(isa, i) != w83781d_read_value(i2c, i))
- return 0;
- }
- if (w83781d_read_value(isa, W83781D_REG_CONFIG) !- w83781d_read_value(i2c, W83781D_REG_CONFIG))
- return 0;
- for (i = 0x43; i <= 0x46; i++) {
- if (w83781d_read_value(isa, i) != w83781d_read_value(i2c, i))
- return 0;
- }
-
- return 1;
-}
-
/* No clean up is done on error, it's up to the caller */
static int
w83781d_create_files(struct device *dev, int kind, int is_isa)
@@ -1167,12 +1107,6 @@ w83781d_create_files(struct device *dev,
}
}
- if (is_isa) {
- err = device_create_file(&pdev->dev, &dev_attr_name);
- if (err)
- return err;
- }
-
return 0;
}
@@ -1381,221 +1315,80 @@ w83781d_detach_client(struct i2c_client
return 0;
}
-static int __devinit
-w83781d_isa_probe(struct platform_device *pdev)
-{
- int err, reg;
- struct w83781d_data *data;
- struct resource *res;
- const char *name;
-
- /* Reserve the ISA region */
- res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2,
- "w83781d")) {
- err = -EBUSY;
- goto exit;
- }
-
- if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit_release_region;
- }
- mutex_init(&data->lock);
- data->client.addr = res->start;
- i2c_set_clientdata(&data->client, data);
- platform_set_drvdata(pdev, data);
-
- reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
- switch (reg) {
- case 0x30:
- data->type = w83782d;
- name = "w83782d";
- break;
- default:
- data->type = w83781d;
- name = "w83781d";
- }
- strlcpy(data->client.name, name, I2C_NAME_SIZE);
-
- /* Initialize the W83781D chip */
- w83781d_init_device(&pdev->dev);
-
- /* Register sysfs hooks */
- err = w83781d_create_files(&pdev->dev, data->type, 1);
- if (err)
- goto exit_remove_files;
-
- data->hwmon_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto exit_remove_files;
- }
-
- return 0;
-
- exit_remove_files:
- sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
- sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
- device_remove_file(&pdev->dev, &dev_attr_name);
- kfree(data);
- exit_release_region:
- release_region(res->start + W83781D_ADDR_REG_OFFSET, 2);
- exit:
- return err;
-}
-
-static int __devexit
-w83781d_isa_remove(struct platform_device *pdev)
-{
- struct w83781d_data *data = platform_get_drvdata(pdev);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
- sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
- device_remove_file(&pdev->dev, &dev_attr_name);
- release_region(data->client.addr + W83781D_ADDR_REG_OFFSET, 2);
- kfree(data);
-
- return 0;
-}
-
-/* The SMBus locks itself, usually, but nothing may access the Winbond between
- bank switches. ISA access must always be locked explicitly!
- We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
- would slow down the W83781D access and should not be necessary.
- There are some ugly typecasts here, but the good news is - they should
- nowhere else be necessary! */
static int
-w83781d_read_value(struct w83781d_data *data, u16 reg)
+w83781d_read_value_i2c(struct w83781d_data *data, u16 reg)
{
struct i2c_client *client = &data->client;
- int res, word_sized, bank;
+ int res, bank;
struct i2c_client *cl;
- mutex_lock(&data->lock);
- if (!client->driver) { /* ISA device */
- word_sized = (((reg & 0xff00) = 0x100)
- || ((reg & 0xff00) = 0x200))
- && (((reg & 0x00ff) = 0x50)
- || ((reg & 0x00ff) = 0x53)
- || ((reg & 0x00ff) = 0x55));
- if (reg & 0xff00) {
- outb_p(W83781D_REG_BANK,
- client->addr + W83781D_ADDR_REG_OFFSET);
- outb_p(reg >> 8,
- client->addr + W83781D_DATA_REG_OFFSET);
- }
- outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
- res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);
- if (word_sized) {
- outb_p((reg & 0xff) + 1,
- client->addr + W83781D_ADDR_REG_OFFSET);
- res - (res << 8) + inb_p(client->addr +
- W83781D_DATA_REG_OFFSET);
- }
- if (reg & 0xff00) {
- outb_p(W83781D_REG_BANK,
- client->addr + W83781D_ADDR_REG_OFFSET);
- outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
- }
+ bank = (reg >> 8) & 0x0f;
+ if (bank > 2)
+ /* switch banks */
+ i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
+ bank);
+ if (bank = 0 || bank > 2) {
+ res = i2c_smbus_read_byte_data(client, reg & 0xff);
} else {
- bank = (reg >> 8) & 0x0f;
- if (bank > 2)
- /* switch banks */
- i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
- bank);
- if (bank = 0 || bank > 2) {
- res = i2c_smbus_read_byte_data(client, reg & 0xff);
- } else {
- /* switch to subclient */
- cl = data->lm75[bank - 1];
- /* convert from ISA to LM75 I2C addresses */
- switch (reg & 0xff) {
- case 0x50: /* TEMP */
- res = swab16(i2c_smbus_read_word_data(cl, 0));
- break;
- case 0x52: /* CONFIG */
- res = i2c_smbus_read_byte_data(cl, 1);
- break;
- case 0x53: /* HYST */
- res = swab16(i2c_smbus_read_word_data(cl, 2));
- break;
- case 0x55: /* OVER */
- default:
- res = swab16(i2c_smbus_read_word_data(cl, 3));
- break;
- }
+ /* switch to subclient */
+ cl = data->lm75[bank - 1];
+ /* convert from ISA to LM75 I2C addresses */
+ switch (reg & 0xff) {
+ case 0x50: /* TEMP */
+ res = swab16(i2c_smbus_read_word_data(cl, 0));
+ break;
+ case 0x52: /* CONFIG */
+ res = i2c_smbus_read_byte_data(cl, 1);
+ break;
+ case 0x53: /* HYST */
+ res = swab16(i2c_smbus_read_word_data(cl, 2));
+ break;
+ case 0x55: /* OVER */
+ default:
+ res = swab16(i2c_smbus_read_word_data(cl, 3));
+ break;
}
- if (bank > 2)
- i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
}
- mutex_unlock(&data->lock);
+ if (bank > 2)
+ i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
+
return res;
}
static int
-w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
+w83781d_write_value_i2c(struct w83781d_data *data, u16 reg, u16 value)
{
struct i2c_client *client = &data->client;
- int word_sized, bank;
struct i2c_client *cl;
+ int bank;
- mutex_lock(&data->lock);
- if (!client->driver) { /* ISA device */
- word_sized = (((reg & 0xff00) = 0x100)
- || ((reg & 0xff00) = 0x200))
- && (((reg & 0x00ff) = 0x53)
- || ((reg & 0x00ff) = 0x55));
- if (reg & 0xff00) {
- outb_p(W83781D_REG_BANK,
- client->addr + W83781D_ADDR_REG_OFFSET);
- outb_p(reg >> 8,
- client->addr + W83781D_DATA_REG_OFFSET);
- }
- outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
- if (word_sized) {
- outb_p(value >> 8,
- client->addr + W83781D_DATA_REG_OFFSET);
- outb_p((reg & 0xff) + 1,
- client->addr + W83781D_ADDR_REG_OFFSET);
- }
- outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET);
- if (reg & 0xff00) {
- outb_p(W83781D_REG_BANK,
- client->addr + W83781D_ADDR_REG_OFFSET);
- outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
- }
+ bank = (reg >> 8) & 0x0f;
+ if (bank > 2)
+ /* switch banks */
+ i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
+ bank);
+ if (bank = 0 || bank > 2) {
+ i2c_smbus_write_byte_data(client, reg & 0xff,
+ value & 0xff);
} else {
- bank = (reg >> 8) & 0x0f;
- if (bank > 2)
- /* switch banks */
- i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
- bank);
- if (bank = 0 || bank > 2) {
- i2c_smbus_write_byte_data(client, reg & 0xff,
- value & 0xff);
- } else {
- /* switch to subclient */
- cl = data->lm75[bank - 1];
- /* convert from ISA to LM75 I2C addresses */
- switch (reg & 0xff) {
- case 0x52: /* CONFIG */
- i2c_smbus_write_byte_data(cl, 1, value & 0xff);
- break;
- case 0x53: /* HYST */
- i2c_smbus_write_word_data(cl, 2, swab16(value));
- break;
- case 0x55: /* OVER */
- i2c_smbus_write_word_data(cl, 3, swab16(value));
- break;
- }
+ /* switch to subclient */
+ cl = data->lm75[bank - 1];
+ /* convert from ISA to LM75 I2C addresses */
+ switch (reg & 0xff) {
+ case 0x52: /* CONFIG */
+ i2c_smbus_write_byte_data(cl, 1, value & 0xff);
+ break;
+ case 0x53: /* HYST */
+ i2c_smbus_write_word_data(cl, 2, swab16(value));
+ break;
+ case 0x55: /* OVER */
+ i2c_smbus_write_word_data(cl, 3, swab16(value));
+ break;
}
- if (bank > 2)
- i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
}
- mutex_unlock(&data->lock);
+ if (bank > 2)
+ i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
+
return 0;
}
@@ -1815,6 +1608,255 @@ static struct w83781d_data *w83781d_upda
return data;
}
+#ifdef CONFIG_ISA
+
+/* ISA device, if found */
+static struct platform_device *pdev;
+
+static unsigned short isa_address = 0x290;
+
+/* I2C devices get this name attribute automatically, but for ISA devices
+ we must create it by ourselves. */
+static ssize_t
+show_name(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct w83781d_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", data->client.name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct w83781d_data *w83781d_data_if_isa(void)
+{
+ return pdev ? platform_get_drvdata(pdev) : NULL;
+}
+
+/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
+static int w83781d_alias_detect(struct i2c_client *client, u8 chipid)
+{
+ struct w83781d_data *i2c, *isa;
+ int i;
+
+ if (!pdev) /* No ISA chip */
+ return 0;
+
+ i2c = i2c_get_clientdata(client);
+ isa = platform_get_drvdata(pdev);
+
+ if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr)
+ return 0; /* Address doesn't match */
+ if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid)
+ return 0; /* Chip type doesn't match */
+
+ /* We compare all the limit registers, the config register and the
+ * interrupt mask registers */
+ for (i = 0x2b; i <= 0x3d; i++) {
+ if (w83781d_read_value(isa, i) != w83781d_read_value(i2c, i))
+ return 0;
+ }
+ if (w83781d_read_value(isa, W83781D_REG_CONFIG) !+ w83781d_read_value(i2c, W83781D_REG_CONFIG))
+ return 0;
+ for (i = 0x43; i <= 0x46; i++) {
+ if (w83781d_read_value(isa, i) != w83781d_read_value(i2c, i))
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+w83781d_read_value_isa(struct w83781d_data *data, u16 reg)
+{
+ struct i2c_client *client = &data->client;
+ int word_sized, res;
+
+ word_sized = (((reg & 0xff00) = 0x100)
+ || ((reg & 0xff00) = 0x200))
+ && (((reg & 0x00ff) = 0x50)
+ || ((reg & 0x00ff) = 0x53)
+ || ((reg & 0x00ff) = 0x55));
+ if (reg & 0xff00) {
+ outb_p(W83781D_REG_BANK,
+ client->addr + W83781D_ADDR_REG_OFFSET);
+ outb_p(reg >> 8,
+ client->addr + W83781D_DATA_REG_OFFSET);
+ }
+ outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
+ res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);
+ if (word_sized) {
+ outb_p((reg & 0xff) + 1,
+ client->addr + W83781D_ADDR_REG_OFFSET);
+ res + (res << 8) + inb_p(client->addr +
+ W83781D_DATA_REG_OFFSET);
+ }
+ if (reg & 0xff00) {
+ outb_p(W83781D_REG_BANK,
+ client->addr + W83781D_ADDR_REG_OFFSET);
+ outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
+ }
+ return res;
+}
+
+static void
+w83781d_write_value_isa(struct w83781d_data *data, u16 reg, u16 value)
+{
+ struct i2c_client *client = &data->client;
+ int word_sized;
+
+ word_sized = (((reg & 0xff00) = 0x100)
+ || ((reg & 0xff00) = 0x200))
+ && (((reg & 0x00ff) = 0x53)
+ || ((reg & 0x00ff) = 0x55));
+ if (reg & 0xff00) {
+ outb_p(W83781D_REG_BANK,
+ client->addr + W83781D_ADDR_REG_OFFSET);
+ outb_p(reg >> 8,
+ client->addr + W83781D_DATA_REG_OFFSET);
+ }
+ outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
+ if (word_sized) {
+ outb_p(value >> 8,
+ client->addr + W83781D_DATA_REG_OFFSET);
+ outb_p((reg & 0xff) + 1,
+ client->addr + W83781D_ADDR_REG_OFFSET);
+ }
+ outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET);
+ if (reg & 0xff00) {
+ outb_p(W83781D_REG_BANK,
+ client->addr + W83781D_ADDR_REG_OFFSET);
+ outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
+ }
+}
+
+/* The SMBus locks itself, usually, but nothing may access the Winbond between
+ bank switches. ISA access must always be locked explicitly!
+ We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
+ would slow down the W83781D access and should not be necessary.
+ There are some ugly typecasts here, but the good news is - they should
+ nowhere else be necessary! */
+static int
+w83781d_read_value(struct w83781d_data *data, u16 reg)
+{
+ struct i2c_client *client = &data->client;
+ int res;
+
+ mutex_lock(&data->lock);
+ if (client->driver)
+ res = w83781d_read_value_i2c(data, reg);
+ else
+ res = w83781d_read_value_isa(data, reg);
+ mutex_unlock(&data->lock);
+ return res;
+}
+
+static int
+w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
+{
+ struct i2c_client *client = &data->client;
+
+ mutex_lock(&data->lock);
+ if (client->driver)
+ w83781d_write_value_i2c(data, reg, value);
+ else
+ w83781d_write_value_isa(data, reg, value);
+ mutex_unlock(&data->lock);
+ return 0;
+}
+
+static int __devinit
+w83781d_isa_probe(struct platform_device *pdev)
+{
+ int err, reg;
+ struct w83781d_data *data;
+ struct resource *res;
+ const char *name;
+
+ /* Reserve the ISA region */
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2,
+ "w83781d")) {
+ err = -EBUSY;
+ goto exit;
+ }
+
+ data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit_release_region;
+ }
+ mutex_init(&data->lock);
+ data->client.addr = res->start;
+ i2c_set_clientdata(&data->client, data);
+ platform_set_drvdata(pdev, data);
+
+ reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
+ switch (reg) {
+ case 0x30:
+ data->type = w83782d;
+ name = "w83782d";
+ break;
+ default:
+ data->type = w83781d;
+ name = "w83781d";
+ }
+ strlcpy(data->client.name, name, I2C_NAME_SIZE);
+
+ /* Initialize the W83781D chip */
+ w83781d_init_device(&pdev->dev);
+
+ /* Register sysfs hooks */
+ err = w83781d_create_files(&pdev->dev, data->type, 1);
+ if (err)
+ goto exit_remove_files;
+
+ err = device_create_file(&pdev->dev, &dev_attr_name);
+ if (err)
+ goto exit_remove_files;
+
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove_files;
+ }
+
+ return 0;
+
+ exit_remove_files:
+ sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
+ sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ kfree(data);
+ exit_release_region:
+ release_region(res->start + W83781D_ADDR_REG_OFFSET, 2);
+ exit:
+ return err;
+}
+
+static int __devexit
+w83781d_isa_remove(struct platform_device *pdev)
+{
+ struct w83781d_data *data = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
+ sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ release_region(data->client.addr + W83781D_ADDR_REG_OFFSET, 2);
+ kfree(data);
+
+ return 0;
+}
+
+static struct platform_driver w83781d_isa_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "w83781d",
+ },
+ .probe = w83781d_isa_probe,
+ .remove = w83781d_isa_remove,
+};
+
/* return 1 if a supported chip is found, 0 otherwise */
static int __init
w83781d_isa_found(unsigned short address)
@@ -1951,12 +1993,10 @@ w83781d_isa_device_add(unsigned short ad
}
static int __init
-sensors_w83781d_init(void)
+w83781d_isa_register(void)
{
int res;
- /* We register the ISA device first, so that we can skip the
- * registration of an I2C interface to the same device. */
if (w83781d_isa_found(isa_address)) {
res = platform_driver_register(&w83781d_isa_driver);
if (res)
@@ -1968,16 +2008,89 @@ sensors_w83781d_init(void)
goto exit_unreg_isa_driver;
}
+ return 0;
+
+exit_unreg_isa_driver:
+ platform_driver_unregister(&w83781d_isa_driver);
+exit:
+ return res;
+
+}
+
+static void __init
+w83781d_isa_unregister(void)
+{
+ if (pdev) {
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&w83781d_isa_driver);
+ }
+}
+#else /* !CONFIG_ISA */
+
+static struct w83781d_data *w83781d_data_if_isa(void)
+{
+ return NULL;
+}
+
+static int
+w83781d_alias_detect(struct i2c_client *client, u8 chipid)
+{
+ return 0;
+}
+
+static int
+w83781d_read_value(struct w83781d_data *data, u16 reg)
+{
+ int res;
+
+ mutex_lock(&data->lock);
+ res = w83781d_read_value_i2c(data, reg);
+ mutex_unlock(&data->lock);
+
+ return res;
+}
+
+static int
+w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
+{
+ mutex_lock(&data->lock);
+ w83781d_write_value_i2c(data, reg, value);
+ mutex_unlock(&data->lock);
+
+ return 0;
+}
+
+static int __init
+w83781d_isa_register(void)
+{
+ return 0;
+}
+
+static void __init
+w83781d_isa_unregister(void)
+{
+}
+#endif /* CONFIG_ISA */
+
+static int __init
+sensors_w83781d_init(void)
+{
+ int res;
+
+ /* We register the ISA device first, so that we can skip the
+ * registration of an I2C interface to the same device. */
+ res = w83781d_isa_register();
+ if (res)
+ goto exit;
+
res = i2c_add_driver(&w83781d_driver);
if (res)
- goto exit_unreg_isa_device;
+ goto exit_unreg_isa;
return 0;
- exit_unreg_isa_device:
- platform_device_unregister(pdev);
- exit_unreg_isa_driver:
- platform_driver_unregister(&w83781d_isa_driver);
+ exit_unreg_isa:
+ w83781d_isa_unregister();
exit:
return res;
}
@@ -1985,10 +2098,7 @@ sensors_w83781d_init(void)
static void __exit
sensors_w83781d_exit(void)
{
- if (pdev) {
- platform_device_unregister(pdev);
- platform_driver_unregister(&w83781d_isa_driver);
- }
+ w83781d_isa_unregister();
i2c_del_driver(&w83781d_driver);
}
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [lm-sensors] [PATCH 1/2] hwmon: w83781d: make ISA interface
2008-09-13 8:53 [lm-sensors] [PATCH 1/2] hwmon: w83781d: make ISA interface depend Wolfgang Grandegger
@ 2008-10-06 13:13 ` Jean Delvare
2008-10-06 13:32 ` Wolfgang Grandegger
1 sibling, 0 replies; 3+ messages in thread
From: Jean Delvare @ 2008-10-06 13:13 UTC (permalink / raw)
To: lm-sensors
Hi Wolfgang,
On Sat, 13 Sep 2008 10:53:01 +0200, Wolfgang Grandegger wrote:
> Probing the ISA bus on systems without ISA bus may hang the system.
> This patch makes the ISA bus related code depend on the kernel
> configuration parameter CONFIG_ISA. It moves ISA bus related code
> into one #ifdef CONFIG_ISA ... #endif block and adds some helper
> function.
As said before, this patch is a little bigger than I hoped for, but I
admit it nicely optimizes the size of the driver when CONFIG_ISA isn't
set. So, so be it, I'm taking it.
>
> Note that this patch is based on the patches:
>
> hwmon-w83781d-01-refactor-beep-enable.patch
> hwmon-w83781d-02-alias-detect.patch
>
> from http://jdelvare.pck.nerim.net/sensors/w83781d/.
>
> Signed-off-by: Wolfgang Grandegger <wg@grandegger.com>
> ---
> drivers/hwmon/w83781d.c | 666 +++++++++++++++++++++++++++---------------------
> 1 file changed, 388 insertions(+), 278 deletions(-)
>
> Index: linux-2.6-denx/drivers/hwmon/w83781d.c
> =================================> --- linux-2.6-denx.orig/drivers/hwmon/w83781d.c
> +++ linux-2.6-denx/drivers/hwmon/w83781d.c
> @@ -49,14 +49,9 @@
> #include <asm/io.h>
> #include "lm75.h"
You can put the inclusion of <linux/platform_device.h>,
<linux/ioport.h> and <asm/io.h> inside #ifdef CONFIG_ISA as well. This
will avoid unneeded rebuilds.
>
> -/* ISA device, if found */
> -static struct platform_device *pdev;
> -
> /* Addresses to scan */
> static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
> 0x2e, 0x2f, I2C_CLIENT_END };
> -static unsigned short isa_address = 0x290;
> -
> /* Insmod parameters */
> I2C_CLIENT_INSMOD_4(w83781d, w83782d, w83783s, as99127f);
> I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
> @@ -245,13 +240,13 @@ struct w83781d_data {
> u8 vrm;
> };
>
> +static struct w83781d_data *w83781d_data_if_isa(void);
> +static int w83781d_alias_detect(struct i2c_client *client, u8 chipid);
> +
> static int w83781d_attach_adapter(struct i2c_adapter *adapter);
> static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind);
> static int w83781d_detach_client(struct i2c_client *client);
>
> -static int __devinit w83781d_isa_probe(struct platform_device *pdev);
> -static int __devexit w83781d_isa_remove(struct platform_device *pdev);
> -
> static int w83781d_read_value(struct w83781d_data *data, u16 reg);
> static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);
> static struct w83781d_data *w83781d_update_device(struct device *dev);
> @@ -265,16 +260,6 @@ static struct i2c_driver w83781d_driver
> .detach_client = w83781d_detach_client,
> };
>
> -static struct platform_driver w83781d_isa_driver = {
> - .driver = {
> - .owner = THIS_MODULE,
> - .name = "w83781d",
> - },
> - .probe = w83781d_isa_probe,
> - .remove = w83781d_isa_remove,
> -};
> -
> -
> /* following are the sysfs callback functions */
> #define show_in_reg(reg) \
> static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
> @@ -836,16 +821,6 @@ static SENSOR_DEVICE_ATTR(temp2_type, S_
> static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
> show_sensor, store_sensor, 2);
>
> -/* I2C devices get this name attribute automatically, but for ISA devices
> - we must create it by ourselves. */
> -static ssize_t
> -show_name(struct device *dev, struct device_attribute *devattr, char *buf)
> -{
> - struct w83781d_data *data = dev_get_drvdata(dev);
> - return sprintf(buf, "%s\n", data->client.name);
> -}
> -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
> -
> /* This function is called when:
> * w83781d_driver is inserted (when this module is loaded), for each
> available adapter
> @@ -855,13 +830,12 @@ static DEVICE_ATTR(name, S_IRUGO, show_n
> static int
> w83781d_attach_adapter(struct i2c_adapter *adapter)
> {
> - struct w83781d_data *data;
> + struct w83781d_data *data = w83781d_data_if_isa();
> int err;
>
> if (!(adapter->class & I2C_CLASS_HWMON))
> return 0;
>
> - data = pdev ? platform_get_drvdata(pdev) : NULL;
> if (data)
> mutex_lock(&data->update_lock);
> err = i2c_probe(adapter, &addr_data, w83781d_detect);
> @@ -1037,40 +1011,6 @@ static const struct attribute_group w837
> .attrs = w83781d_attributes_opt,
> };
>
> -/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
> -static int w83781d_alias_detect(struct i2c_client *client, u8 chipid)
> -{
> - struct w83781d_data *i2c, *isa;
> - int i;
> -
> - if (!pdev) /* No ISA chip */
> - return 0;
> -
> - i2c = i2c_get_clientdata(client);
> - isa = platform_get_drvdata(pdev);
> -
> - if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr)
> - return 0; /* Address doesn't match */
> - if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid)
> - return 0; /* Chip type doesn't match */
> -
> - /* We compare all the limit registers, the config register and the
> - * interrupt mask registers */
> - for (i = 0x2b; i <= 0x3d; i++) {
> - if (w83781d_read_value(isa, i) != w83781d_read_value(i2c, i))
> - return 0;
> - }
> - if (w83781d_read_value(isa, W83781D_REG_CONFIG) !> - w83781d_read_value(i2c, W83781D_REG_CONFIG))
> - return 0;
> - for (i = 0x43; i <= 0x46; i++) {
> - if (w83781d_read_value(isa, i) != w83781d_read_value(i2c, i))
> - return 0;
> - }
> -
> - return 1;
> -}
> -
> /* No clean up is done on error, it's up to the caller */
> static int
> w83781d_create_files(struct device *dev, int kind, int is_isa)
> @@ -1167,12 +1107,6 @@ w83781d_create_files(struct device *dev,
> }
> }
>
> - if (is_isa) {
> - err = device_create_file(&pdev->dev, &dev_attr_name);
> - if (err)
> - return err;
> - }
> -
> return 0;
> }
>
> @@ -1381,221 +1315,80 @@ w83781d_detach_client(struct i2c_client
> return 0;
> }
>
> -static int __devinit
> -w83781d_isa_probe(struct platform_device *pdev)
> -{
> - int err, reg;
> - struct w83781d_data *data;
> - struct resource *res;
> - const char *name;
> -
> - /* Reserve the ISA region */
> - res = platform_get_resource(pdev, IORESOURCE_IO, 0);
> - if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2,
> - "w83781d")) {
> - err = -EBUSY;
> - goto exit;
> - }
> -
> - if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {
> - err = -ENOMEM;
> - goto exit_release_region;
> - }
> - mutex_init(&data->lock);
> - data->client.addr = res->start;
> - i2c_set_clientdata(&data->client, data);
> - platform_set_drvdata(pdev, data);
> -
> - reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
> - switch (reg) {
> - case 0x30:
> - data->type = w83782d;
> - name = "w83782d";
> - break;
> - default:
> - data->type = w83781d;
> - name = "w83781d";
> - }
> - strlcpy(data->client.name, name, I2C_NAME_SIZE);
> -
> - /* Initialize the W83781D chip */
> - w83781d_init_device(&pdev->dev);
> -
> - /* Register sysfs hooks */
> - err = w83781d_create_files(&pdev->dev, data->type, 1);
> - if (err)
> - goto exit_remove_files;
> -
> - data->hwmon_dev = hwmon_device_register(&pdev->dev);
> - if (IS_ERR(data->hwmon_dev)) {
> - err = PTR_ERR(data->hwmon_dev);
> - goto exit_remove_files;
> - }
> -
> - return 0;
> -
> - exit_remove_files:
> - sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
> - sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
> - device_remove_file(&pdev->dev, &dev_attr_name);
> - kfree(data);
> - exit_release_region:
> - release_region(res->start + W83781D_ADDR_REG_OFFSET, 2);
> - exit:
> - return err;
> -}
> -
> -static int __devexit
> -w83781d_isa_remove(struct platform_device *pdev)
> -{
> - struct w83781d_data *data = platform_get_drvdata(pdev);
> -
> - hwmon_device_unregister(data->hwmon_dev);
> - sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
> - sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
> - device_remove_file(&pdev->dev, &dev_attr_name);
> - release_region(data->client.addr + W83781D_ADDR_REG_OFFSET, 2);
> - kfree(data);
> -
> - return 0;
> -}
> -
> -/* The SMBus locks itself, usually, but nothing may access the Winbond between
> - bank switches. ISA access must always be locked explicitly!
> - We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
> - would slow down the W83781D access and should not be necessary.
> - There are some ugly typecasts here, but the good news is - they should
> - nowhere else be necessary! */
> static int
> -w83781d_read_value(struct w83781d_data *data, u16 reg)
> +w83781d_read_value_i2c(struct w83781d_data *data, u16 reg)
> {
> struct i2c_client *client = &data->client;
> - int res, word_sized, bank;
> + int res, bank;
> struct i2c_client *cl;
>
> - mutex_lock(&data->lock);
> - if (!client->driver) { /* ISA device */
> - word_sized = (((reg & 0xff00) = 0x100)
> - || ((reg & 0xff00) = 0x200))
> - && (((reg & 0x00ff) = 0x50)
> - || ((reg & 0x00ff) = 0x53)
> - || ((reg & 0x00ff) = 0x55));
> - if (reg & 0xff00) {
> - outb_p(W83781D_REG_BANK,
> - client->addr + W83781D_ADDR_REG_OFFSET);
> - outb_p(reg >> 8,
> - client->addr + W83781D_DATA_REG_OFFSET);
> - }
> - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
> - res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);
> - if (word_sized) {
> - outb_p((reg & 0xff) + 1,
> - client->addr + W83781D_ADDR_REG_OFFSET);
> - res > - (res << 8) + inb_p(client->addr +
> - W83781D_DATA_REG_OFFSET);
> - }
> - if (reg & 0xff00) {
> - outb_p(W83781D_REG_BANK,
> - client->addr + W83781D_ADDR_REG_OFFSET);
> - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
> - }
> + bank = (reg >> 8) & 0x0f;
> + if (bank > 2)
> + /* switch banks */
> + i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
> + bank);
> + if (bank = 0 || bank > 2) {
> + res = i2c_smbus_read_byte_data(client, reg & 0xff);
> } else {
> - bank = (reg >> 8) & 0x0f;
> - if (bank > 2)
> - /* switch banks */
> - i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
> - bank);
> - if (bank = 0 || bank > 2) {
> - res = i2c_smbus_read_byte_data(client, reg & 0xff);
> - } else {
> - /* switch to subclient */
> - cl = data->lm75[bank - 1];
> - /* convert from ISA to LM75 I2C addresses */
> - switch (reg & 0xff) {
> - case 0x50: /* TEMP */
> - res = swab16(i2c_smbus_read_word_data(cl, 0));
> - break;
> - case 0x52: /* CONFIG */
> - res = i2c_smbus_read_byte_data(cl, 1);
> - break;
> - case 0x53: /* HYST */
> - res = swab16(i2c_smbus_read_word_data(cl, 2));
> - break;
> - case 0x55: /* OVER */
> - default:
> - res = swab16(i2c_smbus_read_word_data(cl, 3));
> - break;
> - }
> + /* switch to subclient */
> + cl = data->lm75[bank - 1];
> + /* convert from ISA to LM75 I2C addresses */
> + switch (reg & 0xff) {
> + case 0x50: /* TEMP */
> + res = swab16(i2c_smbus_read_word_data(cl, 0));
> + break;
> + case 0x52: /* CONFIG */
> + res = i2c_smbus_read_byte_data(cl, 1);
> + break;
> + case 0x53: /* HYST */
> + res = swab16(i2c_smbus_read_word_data(cl, 2));
> + break;
> + case 0x55: /* OVER */
> + default:
> + res = swab16(i2c_smbus_read_word_data(cl, 3));
> + break;
> }
> - if (bank > 2)
> - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
> }
> - mutex_unlock(&data->lock);
> + if (bank > 2)
> + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
> +
> return res;
> }
>
> static int
> -w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
> +w83781d_write_value_i2c(struct w83781d_data *data, u16 reg, u16 value)
> {
> struct i2c_client *client = &data->client;
> - int word_sized, bank;
> struct i2c_client *cl;
> + int bank;
>
> - mutex_lock(&data->lock);
> - if (!client->driver) { /* ISA device */
> - word_sized = (((reg & 0xff00) = 0x100)
> - || ((reg & 0xff00) = 0x200))
> - && (((reg & 0x00ff) = 0x53)
> - || ((reg & 0x00ff) = 0x55));
> - if (reg & 0xff00) {
> - outb_p(W83781D_REG_BANK,
> - client->addr + W83781D_ADDR_REG_OFFSET);
> - outb_p(reg >> 8,
> - client->addr + W83781D_DATA_REG_OFFSET);
> - }
> - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
> - if (word_sized) {
> - outb_p(value >> 8,
> - client->addr + W83781D_DATA_REG_OFFSET);
> - outb_p((reg & 0xff) + 1,
> - client->addr + W83781D_ADDR_REG_OFFSET);
> - }
> - outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET);
> - if (reg & 0xff00) {
> - outb_p(W83781D_REG_BANK,
> - client->addr + W83781D_ADDR_REG_OFFSET);
> - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
> - }
> + bank = (reg >> 8) & 0x0f;
> + if (bank > 2)
> + /* switch banks */
> + i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
> + bank);
> + if (bank = 0 || bank > 2) {
> + i2c_smbus_write_byte_data(client, reg & 0xff,
> + value & 0xff);
> } else {
> - bank = (reg >> 8) & 0x0f;
> - if (bank > 2)
> - /* switch banks */
> - i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
> - bank);
> - if (bank = 0 || bank > 2) {
> - i2c_smbus_write_byte_data(client, reg & 0xff,
> - value & 0xff);
> - } else {
> - /* switch to subclient */
> - cl = data->lm75[bank - 1];
> - /* convert from ISA to LM75 I2C addresses */
> - switch (reg & 0xff) {
> - case 0x52: /* CONFIG */
> - i2c_smbus_write_byte_data(cl, 1, value & 0xff);
> - break;
> - case 0x53: /* HYST */
> - i2c_smbus_write_word_data(cl, 2, swab16(value));
> - break;
> - case 0x55: /* OVER */
> - i2c_smbus_write_word_data(cl, 3, swab16(value));
> - break;
> - }
> + /* switch to subclient */
> + cl = data->lm75[bank - 1];
> + /* convert from ISA to LM75 I2C addresses */
> + switch (reg & 0xff) {
> + case 0x52: /* CONFIG */
> + i2c_smbus_write_byte_data(cl, 1, value & 0xff);
> + break;
> + case 0x53: /* HYST */
> + i2c_smbus_write_word_data(cl, 2, swab16(value));
> + break;
> + case 0x55: /* OVER */
> + i2c_smbus_write_word_data(cl, 3, swab16(value));
> + break;
> }
> - if (bank > 2)
> - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
> }
> - mutex_unlock(&data->lock);
> + if (bank > 2)
> + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
> +
> return 0;
> }
>
> @@ -1815,6 +1608,255 @@ static struct w83781d_data *w83781d_upda
> return data;
> }
>
> +#ifdef CONFIG_ISA
> +
> +/* ISA device, if found */
> +static struct platform_device *pdev;
> +
> +static unsigned short isa_address = 0x290;
> +
> +/* I2C devices get this name attribute automatically, but for ISA devices
> + we must create it by ourselves. */
> +static ssize_t
> +show_name(struct device *dev, struct device_attribute *devattr, char *buf)
> +{
> + struct w83781d_data *data = dev_get_drvdata(dev);
> + return sprintf(buf, "%s\n", data->client.name);
> +}
> +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
> +
> +static struct w83781d_data *w83781d_data_if_isa(void)
> +{
> + return pdev ? platform_get_drvdata(pdev) : NULL;
> +}
> +
> +/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
> +static int w83781d_alias_detect(struct i2c_client *client, u8 chipid)
> +{
> + struct w83781d_data *i2c, *isa;
> + int i;
> +
> + if (!pdev) /* No ISA chip */
> + return 0;
> +
> + i2c = i2c_get_clientdata(client);
> + isa = platform_get_drvdata(pdev);
> +
> + if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr)
> + return 0; /* Address doesn't match */
> + if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid)
> + return 0; /* Chip type doesn't match */
> +
> + /* We compare all the limit registers, the config register and the
> + * interrupt mask registers */
> + for (i = 0x2b; i <= 0x3d; i++) {
> + if (w83781d_read_value(isa, i) != w83781d_read_value(i2c, i))
> + return 0;
> + }
> + if (w83781d_read_value(isa, W83781D_REG_CONFIG) !> + w83781d_read_value(i2c, W83781D_REG_CONFIG))
> + return 0;
> + for (i = 0x43; i <= 0x46; i++) {
> + if (w83781d_read_value(isa, i) != w83781d_read_value(i2c, i))
> + return 0;
> + }
> +
> + return 1;
> +}
> +
> +static int
> +w83781d_read_value_isa(struct w83781d_data *data, u16 reg)
> +{
> + struct i2c_client *client = &data->client;
> + int word_sized, res;
> +
> + word_sized = (((reg & 0xff00) = 0x100)
> + || ((reg & 0xff00) = 0x200))
> + && (((reg & 0x00ff) = 0x50)
> + || ((reg & 0x00ff) = 0x53)
> + || ((reg & 0x00ff) = 0x55));
> + if (reg & 0xff00) {
> + outb_p(W83781D_REG_BANK,
> + client->addr + W83781D_ADDR_REG_OFFSET);
> + outb_p(reg >> 8,
> + client->addr + W83781D_DATA_REG_OFFSET);
> + }
> + outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
> + res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);
> + if (word_sized) {
> + outb_p((reg & 0xff) + 1,
> + client->addr + W83781D_ADDR_REG_OFFSET);
> + res > + (res << 8) + inb_p(client->addr +
> + W83781D_DATA_REG_OFFSET);
> + }
> + if (reg & 0xff00) {
> + outb_p(W83781D_REG_BANK,
> + client->addr + W83781D_ADDR_REG_OFFSET);
> + outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
> + }
> + return res;
> +}
> +
> +static void
> +w83781d_write_value_isa(struct w83781d_data *data, u16 reg, u16 value)
> +{
> + struct i2c_client *client = &data->client;
> + int word_sized;
> +
> + word_sized = (((reg & 0xff00) = 0x100)
> + || ((reg & 0xff00) = 0x200))
> + && (((reg & 0x00ff) = 0x53)
> + || ((reg & 0x00ff) = 0x55));
> + if (reg & 0xff00) {
> + outb_p(W83781D_REG_BANK,
> + client->addr + W83781D_ADDR_REG_OFFSET);
> + outb_p(reg >> 8,
> + client->addr + W83781D_DATA_REG_OFFSET);
> + }
> + outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
> + if (word_sized) {
> + outb_p(value >> 8,
> + client->addr + W83781D_DATA_REG_OFFSET);
> + outb_p((reg & 0xff) + 1,
> + client->addr + W83781D_ADDR_REG_OFFSET);
> + }
> + outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET);
> + if (reg & 0xff00) {
> + outb_p(W83781D_REG_BANK,
> + client->addr + W83781D_ADDR_REG_OFFSET);
> + outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
> + }
> +}
> +
> +/* The SMBus locks itself, usually, but nothing may access the Winbond between
> + bank switches. ISA access must always be locked explicitly!
> + We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
> + would slow down the W83781D access and should not be necessary.
> + There are some ugly typecasts here, but the good news is - they should
> + nowhere else be necessary! */
> +static int
> +w83781d_read_value(struct w83781d_data *data, u16 reg)
> +{
> + struct i2c_client *client = &data->client;
> + int res;
> +
> + mutex_lock(&data->lock);
> + if (client->driver)
> + res = w83781d_read_value_i2c(data, reg);
> + else
> + res = w83781d_read_value_isa(data, reg);
> + mutex_unlock(&data->lock);
> + return res;
> +}
> +
> +static int
> +w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
> +{
> + struct i2c_client *client = &data->client;
> +
> + mutex_lock(&data->lock);
> + if (client->driver)
> + w83781d_write_value_i2c(data, reg, value);
> + else
> + w83781d_write_value_isa(data, reg, value);
> + mutex_unlock(&data->lock);
> + return 0;
> +}
> +
> +static int __devinit
> +w83781d_isa_probe(struct platform_device *pdev)
> +{
> + int err, reg;
> + struct w83781d_data *data;
> + struct resource *res;
> + const char *name;
> +
> + /* Reserve the ISA region */
> + res = platform_get_resource(pdev, IORESOURCE_IO, 0);
> + if (!request_region(res->start + W83781D_ADDR_REG_OFFSET, 2,
> + "w83781d")) {
> + err = -EBUSY;
> + goto exit;
> + }
> +
> + data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL);
> + if (!data) {
> + err = -ENOMEM;
> + goto exit_release_region;
> + }
> + mutex_init(&data->lock);
> + data->client.addr = res->start;
> + i2c_set_clientdata(&data->client, data);
> + platform_set_drvdata(pdev, data);
> +
> + reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
> + switch (reg) {
> + case 0x30:
> + data->type = w83782d;
> + name = "w83782d";
> + break;
> + default:
> + data->type = w83781d;
> + name = "w83781d";
> + }
> + strlcpy(data->client.name, name, I2C_NAME_SIZE);
> +
> + /* Initialize the W83781D chip */
> + w83781d_init_device(&pdev->dev);
> +
> + /* Register sysfs hooks */
> + err = w83781d_create_files(&pdev->dev, data->type, 1);
> + if (err)
> + goto exit_remove_files;
> +
> + err = device_create_file(&pdev->dev, &dev_attr_name);
> + if (err)
> + goto exit_remove_files;
> +
> + data->hwmon_dev = hwmon_device_register(&pdev->dev);
> + if (IS_ERR(data->hwmon_dev)) {
> + err = PTR_ERR(data->hwmon_dev);
> + goto exit_remove_files;
> + }
> +
> + return 0;
> +
> + exit_remove_files:
> + sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
> + sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
> + device_remove_file(&pdev->dev, &dev_attr_name);
> + kfree(data);
> + exit_release_region:
> + release_region(res->start + W83781D_ADDR_REG_OFFSET, 2);
> + exit:
> + return err;
> +}
> +
> +static int __devexit
> +w83781d_isa_remove(struct platform_device *pdev)
> +{
> + struct w83781d_data *data = platform_get_drvdata(pdev);
> +
> + hwmon_device_unregister(data->hwmon_dev);
> + sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
> + sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
> + device_remove_file(&pdev->dev, &dev_attr_name);
> + release_region(data->client.addr + W83781D_ADDR_REG_OFFSET, 2);
> + kfree(data);
> +
> + return 0;
> +}
> +
> +static struct platform_driver w83781d_isa_driver = {
> + .driver = {
> + .owner = THIS_MODULE,
> + .name = "w83781d",
> + },
> + .probe = w83781d_isa_probe,
> + .remove = w83781d_isa_remove,
Missing __devexit_p. Not your fault, the original code had the same
problem.
> +};
> +
> /* return 1 if a supported chip is found, 0 otherwise */
> static int __init
> w83781d_isa_found(unsigned short address)
> @@ -1951,12 +1993,10 @@ w83781d_isa_device_add(unsigned short ad
> }
>
> static int __init
> -sensors_w83781d_init(void)
> +w83781d_isa_register(void)
> {
> int res;
>
> - /* We register the ISA device first, so that we can skip the
> - * registration of an I2C interface to the same device. */
> if (w83781d_isa_found(isa_address)) {
> res = platform_driver_register(&w83781d_isa_driver);
> if (res)
> @@ -1968,16 +2008,89 @@ sensors_w83781d_init(void)
> goto exit_unreg_isa_driver;
> }
>
> + return 0;
> +
> +exit_unreg_isa_driver:
> + platform_driver_unregister(&w83781d_isa_driver);
> +exit:
> + return res;
> +
Extra blank line.
> +}
> +
> +static void __init
Should be __exit not __init.
> +w83781d_isa_unregister(void)
> +{
> + if (pdev) {
> + platform_device_unregister(pdev);
> + platform_driver_unregister(&w83781d_isa_driver);
> + }
> +}
> +#else /* !CONFIG_ISA */
> +
> +static struct w83781d_data *w83781d_data_if_isa(void)
> +{
> + return NULL;
> +}
> +
> +static int
> +w83781d_alias_detect(struct i2c_client *client, u8 chipid)
> +{
> + return 0;
> +}
> +
> +static int
> +w83781d_read_value(struct w83781d_data *data, u16 reg)
> +{
> + int res;
> +
> + mutex_lock(&data->lock);
> + res = w83781d_read_value_i2c(data, reg);
> + mutex_unlock(&data->lock);
> +
> + return res;
> +}
> +
> +static int
> +w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
> +{
> + mutex_lock(&data->lock);
> + w83781d_write_value_i2c(data, reg, value);
> + mutex_unlock(&data->lock);
> +
> + return 0;
> +}
> +
> +static int __init
> +w83781d_isa_register(void)
> +{
> + return 0;
> +}
> +
> +static void __init
Should be __exit not __init.
> +w83781d_isa_unregister(void)
> +{
> +}
> +#endif /* CONFIG_ISA */
> +
> +static int __init
> +sensors_w83781d_init(void)
> +{
> + int res;
> +
> + /* We register the ISA device first, so that we can skip the
> + * registration of an I2C interface to the same device. */
> + res = w83781d_isa_register();
> + if (res)
> + goto exit;
> +
> res = i2c_add_driver(&w83781d_driver);
> if (res)
> - goto exit_unreg_isa_device;
> + goto exit_unreg_isa;
>
> return 0;
>
> - exit_unreg_isa_device:
> - platform_device_unregister(pdev);
> - exit_unreg_isa_driver:
> - platform_driver_unregister(&w83781d_isa_driver);
> + exit_unreg_isa:
> + w83781d_isa_unregister();
> exit:
> return res;
> }
> @@ -1985,10 +2098,7 @@ sensors_w83781d_init(void)
> static void __exit
> sensors_w83781d_exit(void)
> {
> - if (pdev) {
> - platform_device_unregister(pdev);
> - platform_driver_unregister(&w83781d_isa_driver);
> - }
> + w83781d_isa_unregister();
> i2c_del_driver(&w83781d_driver);
> }
>
In order to save some time, I've fixed all these minor issues myself.
Patch tested on my system with an ISA chip and it worked fine. I will
test later with a graphics adapter with a W83781D chip on the same
system.
--
Jean Delvare
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [lm-sensors] [PATCH 1/2] hwmon: w83781d: make ISA interface
2008-09-13 8:53 [lm-sensors] [PATCH 1/2] hwmon: w83781d: make ISA interface depend Wolfgang Grandegger
2008-10-06 13:13 ` [lm-sensors] [PATCH 1/2] hwmon: w83781d: make ISA interface Jean Delvare
@ 2008-10-06 13:32 ` Wolfgang Grandegger
1 sibling, 0 replies; 3+ messages in thread
From: Wolfgang Grandegger @ 2008-10-06 13:32 UTC (permalink / raw)
To: lm-sensors
Hi Jean,
Jean Delvare wrote:
> Hi Wolfgang,
>
> On Sat, 13 Sep 2008 10:53:01 +0200, Wolfgang Grandegger wrote:
>> Probing the ISA bus on systems without ISA bus may hang the system.
>> This patch makes the ISA bus related code depend on the kernel
>> configuration parameter CONFIG_ISA. It moves ISA bus related code
>> into one #ifdef CONFIG_ISA ... #endif block and adds some helper
>> function.
>
> As said before, this patch is a little bigger than I hoped for, but I
> admit it nicely optimizes the size of the driver when CONFIG_ISA isn't
> set. So, so be it, I'm taking it.
Well, the code was not written with separating the ISA interface in mind
and I'm only partially happy with it, to say the least.
>> Note that this patch is based on the patches:
>>
>> hwmon-w83781d-01-refactor-beep-enable.patch
>> hwmon-w83781d-02-alias-detect.patch
>>
>> from http://jdelvare.pck.nerim.net/sensors/w83781d/.
OK, great, thanks.
>> Signed-off-by: Wolfgang Grandegger <wg@grandegger.com>
>> ---
>> drivers/hwmon/w83781d.c | 666 +++++++++++++++++++++++++++---------------------
>> 1 file changed, 388 insertions(+), 278 deletions(-)
>>
>> Index: linux-2.6-denx/drivers/hwmon/w83781d.c
>> =================================>> --- linux-2.6-denx.orig/drivers/hwmon/w83781d.c
>> +++ linux-2.6-denx/drivers/hwmon/w83781d.c
>> @@ -49,14 +49,9 @@
>> #include <asm/io.h>
>> #include "lm75.h"
>
> You can put the inclusion of <linux/platform_device.h>,
> <linux/ioport.h> and <asm/io.h> inside #ifdef CONFIG_ISA as well. This
> will avoid unneeded rebuilds.
Fine for me.
[...deletions...]
>> +static void __init
>
> Should be __exit not __init.
Oops, sorry.
> In order to save some time, I've fixed all these minor issues myself.
>
> Patch tested on my system with an ISA chip and it worked fine. I will
> test later with a graphics adapter with a W83781D chip on the same
> system.
Thanks a lot.
Wolfgang.
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2008-10-06 13:32 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-13 8:53 [lm-sensors] [PATCH 1/2] hwmon: w83781d: make ISA interface depend Wolfgang Grandegger
2008-10-06 13:13 ` [lm-sensors] [PATCH 1/2] hwmon: w83781d: make ISA interface Jean Delvare
2008-10-06 13:32 ` Wolfgang Grandegger
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.