aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/lm78.c78
1 files changed, 65 insertions, 13 deletions
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 2c96d8a548f7..ec601bbf91b9 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -120,10 +120,7 @@ static inline int TEMP_FROM_REG(s8 val)
120 LM78 chips available (well, actually, that is probably never done; but 120 LM78 chips available (well, actually, that is probably never done; but
121 it is a clean illustration of how to handle a case like that). Finally, 121 it is a clean illustration of how to handle a case like that). Finally,
122 a specific chip may be attached to *both* ISA and SMBus, and we would 122 a specific chip may be attached to *both* ISA and SMBus, and we would
123 not like to detect it double. Fortunately, in the case of the LM78 at 123 not like to detect it double. */
124 least, a register tells us what SMBus address we are on, so that helps
125 a bit - except if there could be more than one SMBus. Groan. No solution
126 for this yet. */
127 124
128/* For ISA chips, we abuse the i2c_client addr and name fields. We also use 125/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
129 the driver field to differentiate between I2C and ISA chips. */ 126 the driver field to differentiate between I2C and ISA chips. */
@@ -457,12 +454,24 @@ static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
457/* This function is called when: 454/* This function is called when:
458 * lm78_driver is inserted (when this module is loaded), for each 455 * lm78_driver is inserted (when this module is loaded), for each
459 available adapter 456 available adapter
460 * when a new adapter is inserted (and lm78_driver is still present) */ 457 * when a new adapter is inserted (and lm78_driver is still present)
458 We block updates of the ISA device to minimize the risk of concurrent
459 access to the same LM78 chip through different interfaces. */
461static int lm78_attach_adapter(struct i2c_adapter *adapter) 460static int lm78_attach_adapter(struct i2c_adapter *adapter)
462{ 461{
462 struct lm78_data *data;
463 int err;
464
463 if (!(adapter->class & I2C_CLASS_HWMON)) 465 if (!(adapter->class & I2C_CLASS_HWMON))
464 return 0; 466 return 0;
465 return i2c_probe(adapter, &addr_data, lm78_detect); 467
468 data = pdev ? platform_get_drvdata(pdev) : NULL;
469 if (data)
470 mutex_lock(&data->update_lock);
471 err = i2c_probe(adapter, &addr_data, lm78_detect);
472 if (data)
473 mutex_unlock(&data->update_lock);
474 return err;
466} 475}
467 476
468static struct attribute *lm78_attributes[] = { 477static struct attribute *lm78_attributes[] = {
@@ -531,6 +540,40 @@ static ssize_t show_name(struct device *dev, struct device_attribute
531} 540}
532static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); 541static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
533 542
543/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
544static int lm78_alias_detect(struct i2c_client *client, u8 chipid)
545{
546 struct lm78_data *i2c, *isa;
547 int i;
548
549 if (!pdev) /* No ISA chip */
550 return 0;
551
552 i2c = i2c_get_clientdata(client);
553 isa = platform_get_drvdata(pdev);
554
555 if (lm78_read_value(isa, LM78_REG_I2C_ADDR) != client->addr)
556 return 0; /* Address doesn't match */
557 if ((lm78_read_value(isa, LM78_REG_CHIPID) & 0xfe) != (chipid & 0xfe))
558 return 0; /* Chip type doesn't match */
559
560 /* We compare all the limit registers, the config register and the
561 * interrupt mask registers */
562 for (i = 0x2b; i <= 0x3d; i++) {
563 if (lm78_read_value(isa, i) != lm78_read_value(i2c, i))
564 return 0;
565 }
566 if (lm78_read_value(isa, LM78_REG_CONFIG) !=
567 lm78_read_value(i2c, LM78_REG_CONFIG))
568 return 0;
569 for (i = 0x43; i <= 0x46; i++) {
570 if (lm78_read_value(isa, i) != lm78_read_value(i2c, i))
571 return 0;
572 }
573
574 return 1;
575}
576
534/* This function is called by i2c_probe */ 577/* This function is called by i2c_probe */
535static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) 578static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
536{ 579{
@@ -589,6 +632,13 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
589 err = -ENODEV; 632 err = -ENODEV;
590 goto ERROR2; 633 goto ERROR2;
591 } 634 }
635
636 if (lm78_alias_detect(new_client, i)) {
637 dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
638 "be the same as ISA device\n", address);
639 err = -ENODEV;
640 goto ERROR2;
641 }
592 } 642 }
593 643
594 if (kind == lm78) { 644 if (kind == lm78) {
@@ -959,14 +1009,12 @@ static int __init sm_lm78_init(void)
959{ 1009{
960 int res; 1010 int res;
961 1011
962 res = i2c_add_driver(&lm78_driver); 1012 /* We register the ISA device first, so that we can skip the
963 if (res) 1013 * registration of an I2C interface to the same device. */
964 goto exit;
965
966 if (lm78_isa_found(isa_address)) { 1014 if (lm78_isa_found(isa_address)) {
967 res = platform_driver_register(&lm78_isa_driver); 1015 res = platform_driver_register(&lm78_isa_driver);
968 if (res) 1016 if (res)
969 goto exit_unreg_i2c_driver; 1017 goto exit;
970 1018
971 /* Sets global pdev as a side effect */ 1019 /* Sets global pdev as a side effect */
972 res = lm78_isa_device_add(isa_address); 1020 res = lm78_isa_device_add(isa_address);
@@ -974,12 +1022,16 @@ static int __init sm_lm78_init(void)
974 goto exit_unreg_isa_driver; 1022 goto exit_unreg_isa_driver;
975 } 1023 }
976 1024
1025 res = i2c_add_driver(&lm78_driver);
1026 if (res)
1027 goto exit_unreg_isa_device;
1028
977 return 0; 1029 return 0;
978 1030
1031 exit_unreg_isa_device:
1032 platform_device_unregister(pdev);
979 exit_unreg_isa_driver: 1033 exit_unreg_isa_driver:
980 platform_driver_unregister(&lm78_isa_driver); 1034 platform_driver_unregister(&lm78_isa_driver);
981 exit_unreg_i2c_driver:
982 i2c_del_driver(&lm78_driver);
983 exit: 1035 exit:
984 return res; 1036 return res;
985} 1037}