diff options
-rw-r--r-- | drivers/hwmon/w83781d.c | 79 |
1 files changed, 66 insertions, 13 deletions
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 136bec3fd645..1c00d9f7c14d 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c | |||
@@ -205,10 +205,7 @@ DIV_TO_REG(long val, enum chips type) | |||
205 | W83781D chips available (well, actually, that is probably never done; but | 205 | W83781D chips available (well, actually, that is probably never done; but |
206 | it is a clean illustration of how to handle a case like that). Finally, | 206 | it is a clean illustration of how to handle a case like that). Finally, |
207 | a specific chip may be attached to *both* ISA and SMBus, and we would | 207 | a specific chip may be attached to *both* ISA and SMBus, and we would |
208 | not like to detect it double. Fortunately, in the case of the W83781D at | 208 | not like to detect it double. */ |
209 | least, a register tells us what SMBus address we are on, so that helps | ||
210 | a bit - except if there could be more than one SMBus. Groan. No solution | ||
211 | for this yet. */ | ||
212 | 209 | ||
213 | /* For ISA chips, we abuse the i2c_client addr and name fields. We also use | 210 | /* For ISA chips, we abuse the i2c_client addr and name fields. We also use |
214 | the driver field to differentiate between I2C and ISA chips. */ | 211 | the driver field to differentiate between I2C and ISA chips. */ |
@@ -852,13 +849,25 @@ static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | |||
852 | /* This function is called when: | 849 | /* This function is called when: |
853 | * w83781d_driver is inserted (when this module is loaded), for each | 850 | * w83781d_driver is inserted (when this module is loaded), for each |
854 | available adapter | 851 | available adapter |
855 | * when a new adapter is inserted (and w83781d_driver is still present) */ | 852 | * when a new adapter is inserted (and w83781d_driver is still present) |
853 | We block updates of the ISA device to minimize the risk of concurrent | ||
854 | access to the same W83781D chip through different interfaces. */ | ||
856 | static int | 855 | static int |
857 | w83781d_attach_adapter(struct i2c_adapter *adapter) | 856 | w83781d_attach_adapter(struct i2c_adapter *adapter) |
858 | { | 857 | { |
858 | struct w83781d_data *data; | ||
859 | int err; | ||
860 | |||
859 | if (!(adapter->class & I2C_CLASS_HWMON)) | 861 | if (!(adapter->class & I2C_CLASS_HWMON)) |
860 | return 0; | 862 | return 0; |
861 | return i2c_probe(adapter, &addr_data, w83781d_detect); | 863 | |
864 | data = pdev ? platform_get_drvdata(pdev) : NULL; | ||
865 | if (data) | ||
866 | mutex_lock(&data->update_lock); | ||
867 | err = i2c_probe(adapter, &addr_data, w83781d_detect); | ||
868 | if (data) | ||
869 | mutex_unlock(&data->update_lock); | ||
870 | return err; | ||
862 | } | 871 | } |
863 | 872 | ||
864 | /* Assumes that adapter is of I2C, not ISA variety. | 873 | /* Assumes that adapter is of I2C, not ISA variety. |
@@ -1028,6 +1037,40 @@ static const struct attribute_group w83781d_group_opt = { | |||
1028 | .attrs = w83781d_attributes_opt, | 1037 | .attrs = w83781d_attributes_opt, |
1029 | }; | 1038 | }; |
1030 | 1039 | ||
1040 | /* Returns 1 if the I2C chip appears to be an alias of the ISA chip */ | ||
1041 | static int w83781d_alias_detect(struct i2c_client *client, u8 chipid) | ||
1042 | { | ||
1043 | struct w83781d_data *i2c, *isa; | ||
1044 | int i; | ||
1045 | |||
1046 | if (!pdev) /* No ISA chip */ | ||
1047 | return 0; | ||
1048 | |||
1049 | i2c = i2c_get_clientdata(client); | ||
1050 | isa = platform_get_drvdata(pdev); | ||
1051 | |||
1052 | if (w83781d_read_value(isa, W83781D_REG_I2C_ADDR) != client->addr) | ||
1053 | return 0; /* Address doesn't match */ | ||
1054 | if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid) | ||
1055 | return 0; /* Chip type doesn't match */ | ||
1056 | |||
1057 | /* We compare all the limit registers, the config register and the | ||
1058 | * interrupt mask registers */ | ||
1059 | for (i = 0x2b; i <= 0x3d; i++) { | ||
1060 | if (w83781d_read_value(isa, i) != w83781d_read_value(i2c, i)) | ||
1061 | return 0; | ||
1062 | } | ||
1063 | if (w83781d_read_value(isa, W83781D_REG_CONFIG) != | ||
1064 | w83781d_read_value(i2c, W83781D_REG_CONFIG)) | ||
1065 | return 0; | ||
1066 | for (i = 0x43; i <= 0x46; i++) { | ||
1067 | if (w83781d_read_value(isa, i) != w83781d_read_value(i2c, i)) | ||
1068 | return 0; | ||
1069 | } | ||
1070 | |||
1071 | return 1; | ||
1072 | } | ||
1073 | |||
1031 | /* No clean up is done on error, it's up to the caller */ | 1074 | /* No clean up is done on error, it's up to the caller */ |
1032 | static int | 1075 | static int |
1033 | w83781d_create_files(struct device *dev, int kind, int is_isa) | 1076 | w83781d_create_files(struct device *dev, int kind, int is_isa) |
@@ -1242,6 +1285,14 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) | |||
1242 | err = -EINVAL; | 1285 | err = -EINVAL; |
1243 | goto ERROR2; | 1286 | goto ERROR2; |
1244 | } | 1287 | } |
1288 | |||
1289 | if ((kind == w83781d || kind == w83782d) | ||
1290 | && w83781d_alias_detect(client, val1)) { | ||
1291 | dev_dbg(&adapter->dev, "Device at 0x%02x appears to " | ||
1292 | "be the same as ISA device\n", address); | ||
1293 | err = -ENODEV; | ||
1294 | goto ERROR2; | ||
1295 | } | ||
1245 | } | 1296 | } |
1246 | 1297 | ||
1247 | if (kind == w83781d) { | 1298 | if (kind == w83781d) { |
@@ -1904,14 +1955,12 @@ sensors_w83781d_init(void) | |||
1904 | { | 1955 | { |
1905 | int res; | 1956 | int res; |
1906 | 1957 | ||
1907 | res = i2c_add_driver(&w83781d_driver); | 1958 | /* We register the ISA device first, so that we can skip the |
1908 | if (res) | 1959 | * registration of an I2C interface to the same device. */ |
1909 | goto exit; | ||
1910 | |||
1911 | if (w83781d_isa_found(isa_address)) { | 1960 | if (w83781d_isa_found(isa_address)) { |
1912 | res = platform_driver_register(&w83781d_isa_driver); | 1961 | res = platform_driver_register(&w83781d_isa_driver); |
1913 | if (res) | 1962 | if (res) |
1914 | goto exit_unreg_i2c_driver; | 1963 | goto exit; |
1915 | 1964 | ||
1916 | /* Sets global pdev as a side effect */ | 1965 | /* Sets global pdev as a side effect */ |
1917 | res = w83781d_isa_device_add(isa_address); | 1966 | res = w83781d_isa_device_add(isa_address); |
@@ -1919,12 +1968,16 @@ sensors_w83781d_init(void) | |||
1919 | goto exit_unreg_isa_driver; | 1968 | goto exit_unreg_isa_driver; |
1920 | } | 1969 | } |
1921 | 1970 | ||
1971 | res = i2c_add_driver(&w83781d_driver); | ||
1972 | if (res) | ||
1973 | goto exit_unreg_isa_device; | ||
1974 | |||
1922 | return 0; | 1975 | return 0; |
1923 | 1976 | ||
1977 | exit_unreg_isa_device: | ||
1978 | platform_device_unregister(pdev); | ||
1924 | exit_unreg_isa_driver: | 1979 | exit_unreg_isa_driver: |
1925 | platform_driver_unregister(&w83781d_isa_driver); | 1980 | platform_driver_unregister(&w83781d_isa_driver); |
1926 | exit_unreg_i2c_driver: | ||
1927 | i2c_del_driver(&w83781d_driver); | ||
1928 | exit: | 1981 | exit: |
1929 | return res; | 1982 | return res; |
1930 | } | 1983 | } |