diff options
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/lm78.c | 78 |
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. */ | ||
461 | static int lm78_attach_adapter(struct i2c_adapter *adapter) | 460 | static 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 | ||
468 | static struct attribute *lm78_attributes[] = { | 477 | static struct attribute *lm78_attributes[] = { |
@@ -531,6 +540,40 @@ static ssize_t show_name(struct device *dev, struct device_attribute | |||
531 | } | 540 | } |
532 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | 541 | static 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 */ | ||
544 | static 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 */ |
535 | static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) | 578 | static 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 | } |