diff options
| author | Jean Delvare <khali@linux-fr.org> | 2008-07-16 13:30:11 -0400 |
|---|---|---|
| committer | Jean Delvare <khali@mahadeva.delvare> | 2008-07-16 13:30:11 -0400 |
| commit | 063675b15608dfbb8404b3a19546d579bd039d02 (patch) | |
| tree | e3d00f1e141ef0e2718983ad27f48ea18ee5c2ac | |
| parent | eea54766c6e3f9850affa91061164aeb6bba44b6 (diff) | |
hwmon: (asb100) Convert to a new-style i2c driver
The new-style asb100 driver implements the optional detect() callback
to cover the use cases of the legacy driver.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
| -rw-r--r-- | drivers/hwmon/asb100.c | 207 |
1 files changed, 83 insertions, 124 deletions
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index fe2eea4d799..8a45a2e6ba8 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c | |||
| @@ -176,10 +176,8 @@ static u8 DIV_TO_REG(long val) | |||
| 176 | data is pointed to by client->data. The structure itself is | 176 | data is pointed to by client->data. The structure itself is |
| 177 | dynamically allocated, at the same time the client itself is allocated. */ | 177 | dynamically allocated, at the same time the client itself is allocated. */ |
| 178 | struct asb100_data { | 178 | struct asb100_data { |
| 179 | struct i2c_client client; | ||
| 180 | struct device *hwmon_dev; | 179 | struct device *hwmon_dev; |
| 181 | struct mutex lock; | 180 | struct mutex lock; |
| 182 | enum chips type; | ||
| 183 | 181 | ||
| 184 | struct mutex update_lock; | 182 | struct mutex update_lock; |
| 185 | unsigned long last_updated; /* In jiffies */ | 183 | unsigned long last_updated; /* In jiffies */ |
| @@ -206,18 +204,30 @@ struct asb100_data { | |||
| 206 | static int asb100_read_value(struct i2c_client *client, u16 reg); | 204 | static int asb100_read_value(struct i2c_client *client, u16 reg); |
| 207 | static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val); | 205 | static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val); |
| 208 | 206 | ||
| 209 | static int asb100_attach_adapter(struct i2c_adapter *adapter); | 207 | static int asb100_probe(struct i2c_client *client, |
| 210 | static int asb100_detect(struct i2c_adapter *adapter, int address, int kind); | 208 | const struct i2c_device_id *id); |
| 211 | static int asb100_detach_client(struct i2c_client *client); | 209 | static int asb100_detect(struct i2c_client *client, int kind, |
| 210 | struct i2c_board_info *info); | ||
| 211 | static int asb100_remove(struct i2c_client *client); | ||
| 212 | static struct asb100_data *asb100_update_device(struct device *dev); | 212 | static struct asb100_data *asb100_update_device(struct device *dev); |
| 213 | static void asb100_init_client(struct i2c_client *client); | 213 | static void asb100_init_client(struct i2c_client *client); |
| 214 | 214 | ||
| 215 | static const struct i2c_device_id asb100_id[] = { | ||
| 216 | { "asb100", asb100 }, | ||
| 217 | { } | ||
| 218 | }; | ||
| 219 | MODULE_DEVICE_TABLE(i2c, asb100_id); | ||
| 220 | |||
| 215 | static struct i2c_driver asb100_driver = { | 221 | static struct i2c_driver asb100_driver = { |
| 222 | .class = I2C_CLASS_HWMON, | ||
| 216 | .driver = { | 223 | .driver = { |
| 217 | .name = "asb100", | 224 | .name = "asb100", |
| 218 | }, | 225 | }, |
| 219 | .attach_adapter = asb100_attach_adapter, | 226 | .probe = asb100_probe, |
| 220 | .detach_client = asb100_detach_client, | 227 | .remove = asb100_remove, |
| 228 | .id_table = asb100_id, | ||
| 229 | .detect = asb100_detect, | ||
| 230 | .address_data = &addr_data, | ||
| 221 | }; | 231 | }; |
| 222 | 232 | ||
| 223 | /* 7 Voltages */ | 233 | /* 7 Voltages */ |
| @@ -619,35 +629,13 @@ static const struct attribute_group asb100_group = { | |||
| 619 | .attrs = asb100_attributes, | 629 | .attrs = asb100_attributes, |
| 620 | }; | 630 | }; |
| 621 | 631 | ||
| 622 | /* This function is called when: | 632 | static int asb100_detect_subclients(struct i2c_client *client) |
| 623 | asb100_driver is inserted (when this module is loaded), for each | ||
| 624 | available adapter | ||
| 625 | when a new adapter is inserted (and asb100_driver is still present) | ||
| 626 | */ | ||
| 627 | static int asb100_attach_adapter(struct i2c_adapter *adapter) | ||
| 628 | { | ||
| 629 | if (!(adapter->class & I2C_CLASS_HWMON)) | ||
| 630 | return 0; | ||
| 631 | return i2c_probe(adapter, &addr_data, asb100_detect); | ||
| 632 | } | ||
| 633 | |||
| 634 | static int asb100_detect_subclients(struct i2c_adapter *adapter, int address, | ||
| 635 | int kind, struct i2c_client *client) | ||
| 636 | { | 633 | { |
| 637 | int i, id, err; | 634 | int i, id, err; |
| 635 | int address = client->addr; | ||
| 636 | unsigned short sc_addr[2]; | ||
| 638 | struct asb100_data *data = i2c_get_clientdata(client); | 637 | struct asb100_data *data = i2c_get_clientdata(client); |
| 639 | 638 | struct i2c_adapter *adapter = client->adapter; | |
| 640 | data->lm75[0] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); | ||
| 641 | if (!(data->lm75[0])) { | ||
| 642 | err = -ENOMEM; | ||
| 643 | goto ERROR_SC_0; | ||
| 644 | } | ||
| 645 | |||
| 646 | data->lm75[1] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); | ||
| 647 | if (!(data->lm75[1])) { | ||
| 648 | err = -ENOMEM; | ||
| 649 | goto ERROR_SC_1; | ||
| 650 | } | ||
| 651 | 639 | ||
| 652 | id = i2c_adapter_id(adapter); | 640 | id = i2c_adapter_id(adapter); |
| 653 | 641 | ||
| @@ -665,37 +653,34 @@ static int asb100_detect_subclients(struct i2c_adapter *adapter, int address, | |||
| 665 | asb100_write_value(client, ASB100_REG_I2C_SUBADDR, | 653 | asb100_write_value(client, ASB100_REG_I2C_SUBADDR, |
| 666 | (force_subclients[2] & 0x07) | | 654 | (force_subclients[2] & 0x07) | |
| 667 | ((force_subclients[3] & 0x07) << 4)); | 655 | ((force_subclients[3] & 0x07) << 4)); |
| 668 | data->lm75[0]->addr = force_subclients[2]; | 656 | sc_addr[0] = force_subclients[2]; |
| 669 | data->lm75[1]->addr = force_subclients[3]; | 657 | sc_addr[1] = force_subclients[3]; |
| 670 | } else { | 658 | } else { |
| 671 | int val = asb100_read_value(client, ASB100_REG_I2C_SUBADDR); | 659 | int val = asb100_read_value(client, ASB100_REG_I2C_SUBADDR); |
| 672 | data->lm75[0]->addr = 0x48 + (val & 0x07); | 660 | sc_addr[0] = 0x48 + (val & 0x07); |
| 673 | data->lm75[1]->addr = 0x48 + ((val >> 4) & 0x07); | 661 | sc_addr[1] = 0x48 + ((val >> 4) & 0x07); |
| 674 | } | 662 | } |
| 675 | 663 | ||
| 676 | if (data->lm75[0]->addr == data->lm75[1]->addr) { | 664 | if (sc_addr[0] == sc_addr[1]) { |
| 677 | dev_err(&client->dev, "duplicate addresses 0x%x " | 665 | dev_err(&client->dev, "duplicate addresses 0x%x " |
| 678 | "for subclients\n", data->lm75[0]->addr); | 666 | "for subclients\n", sc_addr[0]); |
| 679 | err = -ENODEV; | 667 | err = -ENODEV; |
| 680 | goto ERROR_SC_2; | 668 | goto ERROR_SC_2; |
| 681 | } | 669 | } |
| 682 | 670 | ||
| 683 | for (i = 0; i <= 1; i++) { | 671 | data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]); |
| 684 | i2c_set_clientdata(data->lm75[i], NULL); | 672 | if (!data->lm75[0]) { |
| 685 | data->lm75[i]->adapter = adapter; | ||
| 686 | data->lm75[i]->driver = &asb100_driver; | ||
| 687 | strlcpy(data->lm75[i]->name, "asb100 subclient", I2C_NAME_SIZE); | ||
| 688 | } | ||
| 689 | |||
| 690 | if ((err = i2c_attach_client(data->lm75[0]))) { | ||
| 691 | dev_err(&client->dev, "subclient %d registration " | 673 | dev_err(&client->dev, "subclient %d registration " |
| 692 | "at address 0x%x failed.\n", i, data->lm75[0]->addr); | 674 | "at address 0x%x failed.\n", 1, sc_addr[0]); |
| 675 | err = -ENOMEM; | ||
| 693 | goto ERROR_SC_2; | 676 | goto ERROR_SC_2; |
| 694 | } | 677 | } |
| 695 | 678 | ||
| 696 | if ((err = i2c_attach_client(data->lm75[1]))) { | 679 | data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]); |
| 680 | if (!data->lm75[1]) { | ||
| 697 | dev_err(&client->dev, "subclient %d registration " | 681 | dev_err(&client->dev, "subclient %d registration " |
| 698 | "at address 0x%x failed.\n", i, data->lm75[1]->addr); | 682 | "at address 0x%x failed.\n", 2, sc_addr[1]); |
| 683 | err = -ENOMEM; | ||
| 699 | goto ERROR_SC_3; | 684 | goto ERROR_SC_3; |
| 700 | } | 685 | } |
| 701 | 686 | ||
| @@ -703,55 +688,31 @@ static int asb100_detect_subclients(struct i2c_adapter *adapter, int address, | |||
| 703 | 688 | ||
| 704 | /* Undo inits in case of errors */ | 689 | /* Undo inits in case of errors */ |
| 705 | ERROR_SC_3: | 690 | ERROR_SC_3: |
| 706 | i2c_detach_client(data->lm75[0]); | 691 | i2c_unregister_device(data->lm75[0]); |
| 707 | ERROR_SC_2: | 692 | ERROR_SC_2: |
| 708 | kfree(data->lm75[1]); | ||
| 709 | ERROR_SC_1: | ||
| 710 | kfree(data->lm75[0]); | ||
| 711 | ERROR_SC_0: | ||
| 712 | return err; | 693 | return err; |
| 713 | } | 694 | } |
| 714 | 695 | ||
| 715 | static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) | 696 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
| 697 | static int asb100_detect(struct i2c_client *client, int kind, | ||
| 698 | struct i2c_board_info *info) | ||
| 716 | { | 699 | { |
| 717 | int err; | 700 | struct i2c_adapter *adapter = client->adapter; |
| 718 | struct i2c_client *client; | ||
| 719 | struct asb100_data *data; | ||
| 720 | 701 | ||
| 721 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | 702 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { |
| 722 | pr_debug("asb100.o: detect failed, " | 703 | pr_debug("asb100.o: detect failed, " |
| 723 | "smbus byte data not supported!\n"); | 704 | "smbus byte data not supported!\n"); |
| 724 | err = -ENODEV; | 705 | return -ENODEV; |
| 725 | goto ERROR0; | ||
| 726 | } | 706 | } |
| 727 | 707 | ||
| 728 | /* OK. For now, we presume we have a valid client. We now create the | ||
| 729 | client structure, even though we cannot fill it completely yet. | ||
| 730 | But it allows us to access asb100_{read,write}_value. */ | ||
| 731 | |||
| 732 | if (!(data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL))) { | ||
| 733 | pr_debug("asb100.o: detect failed, kzalloc failed!\n"); | ||
| 734 | err = -ENOMEM; | ||
| 735 | goto ERROR0; | ||
| 736 | } | ||
| 737 | |||
| 738 | client = &data->client; | ||
| 739 | mutex_init(&data->lock); | ||
| 740 | i2c_set_clientdata(client, data); | ||
| 741 | client->addr = address; | ||
| 742 | client->adapter = adapter; | ||
| 743 | client->driver = &asb100_driver; | ||
| 744 | |||
| 745 | /* Now, we do the remaining detection. */ | ||
| 746 | |||
| 747 | /* The chip may be stuck in some other bank than bank 0. This may | 708 | /* The chip may be stuck in some other bank than bank 0. This may |
| 748 | make reading other information impossible. Specify a force=... or | 709 | make reading other information impossible. Specify a force=... or |
| 749 | force_*=... parameter, and the chip will be reset to the right | 710 | force_*=... parameter, and the chip will be reset to the right |
| 750 | bank. */ | 711 | bank. */ |
| 751 | if (kind < 0) { | 712 | if (kind < 0) { |
| 752 | 713 | ||
| 753 | int val1 = asb100_read_value(client, ASB100_REG_BANK); | 714 | int val1 = i2c_smbus_read_byte_data(client, ASB100_REG_BANK); |
| 754 | int val2 = asb100_read_value(client, ASB100_REG_CHIPMAN); | 715 | int val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN); |
| 755 | 716 | ||
| 756 | /* If we're in bank 0 */ | 717 | /* If we're in bank 0 */ |
| 757 | if ((!(val1 & 0x07)) && | 718 | if ((!(val1 & 0x07)) && |
| @@ -761,48 +722,60 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) | |||
| 761 | ((val1 & 0x80) && (val2 != 0x06)))) { | 722 | ((val1 & 0x80) && (val2 != 0x06)))) { |
| 762 | pr_debug("asb100.o: detect failed, " | 723 | pr_debug("asb100.o: detect failed, " |
| 763 | "bad chip id 0x%02x!\n", val2); | 724 | "bad chip id 0x%02x!\n", val2); |
| 764 | err = -ENODEV; | 725 | return -ENODEV; |
| 765 | goto ERROR1; | ||
| 766 | } | 726 | } |
| 767 | 727 | ||
| 768 | } /* kind < 0 */ | 728 | } /* kind < 0 */ |
| 769 | 729 | ||
| 770 | /* We have either had a force parameter, or we have already detected | 730 | /* We have either had a force parameter, or we have already detected |
| 771 | Winbond. Put it now into bank 0 and Vendor ID High Byte */ | 731 | Winbond. Put it now into bank 0 and Vendor ID High Byte */ |
| 772 | asb100_write_value(client, ASB100_REG_BANK, | 732 | i2c_smbus_write_byte_data(client, ASB100_REG_BANK, |
| 773 | (asb100_read_value(client, ASB100_REG_BANK) & 0x78) | 0x80); | 733 | (i2c_smbus_read_byte_data(client, ASB100_REG_BANK) & 0x78) |
| 734 | | 0x80); | ||
| 774 | 735 | ||
| 775 | /* Determine the chip type. */ | 736 | /* Determine the chip type. */ |
| 776 | if (kind <= 0) { | 737 | if (kind <= 0) { |
| 777 | int val1 = asb100_read_value(client, ASB100_REG_WCHIPID); | 738 | int val1 = i2c_smbus_read_byte_data(client, ASB100_REG_WCHIPID); |
| 778 | int val2 = asb100_read_value(client, ASB100_REG_CHIPMAN); | 739 | int val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN); |
| 779 | 740 | ||
| 780 | if ((val1 == 0x31) && (val2 == 0x06)) | 741 | if ((val1 == 0x31) && (val2 == 0x06)) |
| 781 | kind = asb100; | 742 | kind = asb100; |
| 782 | else { | 743 | else { |
| 783 | if (kind == 0) | 744 | if (kind == 0) |
| 784 | dev_warn(&client->dev, "ignoring " | 745 | dev_warn(&adapter->dev, "ignoring " |
| 785 | "'force' parameter for unknown chip " | 746 | "'force' parameter for unknown chip " |
| 786 | "at adapter %d, address 0x%02x.\n", | 747 | "at adapter %d, address 0x%02x.\n", |
| 787 | i2c_adapter_id(adapter), address); | 748 | i2c_adapter_id(adapter), client->addr); |
| 788 | err = -ENODEV; | 749 | return -ENODEV; |
| 789 | goto ERROR1; | ||
| 790 | } | 750 | } |
| 791 | } | 751 | } |
| 792 | 752 | ||
| 793 | /* Fill in remaining client fields and put it into the global list */ | 753 | strlcpy(info->type, "asb100", I2C_NAME_SIZE); |
| 794 | strlcpy(client->name, "asb100", I2C_NAME_SIZE); | ||
| 795 | data->type = kind; | ||
| 796 | mutex_init(&data->update_lock); | ||
| 797 | 754 | ||
| 798 | /* Tell the I2C layer a new client has arrived */ | 755 | return 0; |
| 799 | if ((err = i2c_attach_client(client))) | 756 | } |
| 800 | goto ERROR1; | 757 | |
| 758 | static int asb100_probe(struct i2c_client *client, | ||
| 759 | const struct i2c_device_id *id) | ||
| 760 | { | ||
| 761 | int err; | ||
| 762 | struct asb100_data *data; | ||
| 763 | |||
| 764 | data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL); | ||
| 765 | if (!data) { | ||
| 766 | pr_debug("asb100.o: probe failed, kzalloc failed!\n"); | ||
| 767 | err = -ENOMEM; | ||
| 768 | goto ERROR0; | ||
| 769 | } | ||
| 770 | |||
| 771 | i2c_set_clientdata(client, data); | ||
| 772 | mutex_init(&data->lock); | ||
| 773 | mutex_init(&data->update_lock); | ||
| 801 | 774 | ||
| 802 | /* Attach secondary lm75 clients */ | 775 | /* Attach secondary lm75 clients */ |
| 803 | if ((err = asb100_detect_subclients(adapter, address, kind, | 776 | err = asb100_detect_subclients(client); |
| 804 | client))) | 777 | if (err) |
| 805 | goto ERROR2; | 778 | goto ERROR1; |
| 806 | 779 | ||
| 807 | /* Initialize the chip */ | 780 | /* Initialize the chip */ |
| 808 | asb100_init_client(client); | 781 | asb100_init_client(client); |
| @@ -827,39 +800,25 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) | |||
| 827 | ERROR4: | 800 | ERROR4: |
| 828 | sysfs_remove_group(&client->dev.kobj, &asb100_group); | 801 | sysfs_remove_group(&client->dev.kobj, &asb100_group); |
| 829 | ERROR3: | 802 | ERROR3: |
| 830 | i2c_detach_client(data->lm75[1]); | 803 | i2c_unregister_device(data->lm75[1]); |
| 831 | i2c_detach_client(data->lm75[0]); | 804 | i2c_unregister_device(data->lm75[0]); |
| 832 | kfree(data->lm75[1]); | ||
| 833 | kfree(data->lm75[0]); | ||
| 834 | ERROR2: | ||
| 835 | i2c_detach_client(client); | ||
| 836 | ERROR1: | 805 | ERROR1: |
| 837 | kfree(data); | 806 | kfree(data); |
| 838 | ERROR0: | 807 | ERROR0: |
| 839 | return err; | 808 | return err; |
| 840 | } | 809 | } |
| 841 | 810 | ||
| 842 | static int asb100_detach_client(struct i2c_client *client) | 811 | static int asb100_remove(struct i2c_client *client) |
| 843 | { | 812 | { |
| 844 | struct asb100_data *data = i2c_get_clientdata(client); | 813 | struct asb100_data *data = i2c_get_clientdata(client); |
| 845 | int err; | ||
| 846 | |||
| 847 | /* main client */ | ||
| 848 | if (data) { | ||
| 849 | hwmon_device_unregister(data->hwmon_dev); | ||
| 850 | sysfs_remove_group(&client->dev.kobj, &asb100_group); | ||
| 851 | } | ||
| 852 | 814 | ||
| 853 | if ((err = i2c_detach_client(client))) | 815 | hwmon_device_unregister(data->hwmon_dev); |
| 854 | return err; | 816 | sysfs_remove_group(&client->dev.kobj, &asb100_group); |
| 855 | 817 | ||
| 856 | /* main client */ | 818 | i2c_unregister_device(data->lm75[1]); |
| 857 | if (data) | 819 | i2c_unregister_device(data->lm75[0]); |
| 858 | kfree(data); | ||
| 859 | 820 | ||
| 860 | /* subclient */ | 821 | kfree(data); |
| 861 | else | ||
| 862 | kfree(client); | ||
| 863 | 822 | ||
| 864 | return 0; | 823 | return 0; |
| 865 | } | 824 | } |
