diff options
Diffstat (limited to 'drivers/hwmon/pmbus/pmbus_core.c')
-rw-r--r-- | drivers/hwmon/pmbus/pmbus_core.c | 140 |
1 files changed, 31 insertions, 109 deletions
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 3782fda21c8b..26b699a6abb9 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c | |||
@@ -31,39 +31,10 @@ | |||
31 | #include "pmbus.h" | 31 | #include "pmbus.h" |
32 | 32 | ||
33 | /* | 33 | /* |
34 | * Constants needed to determine number of sensors, booleans, and labels. | 34 | * Number of additional attribute pointers to allocate |
35 | * with each call to krealloc | ||
35 | */ | 36 | */ |
36 | #define PMBUS_MAX_INPUT_SENSORS 22 /* 10*volt, 7*curr, 5*power */ | 37 | #define PMBUS_ATTR_ALLOC_SIZE 32 |
37 | #define PMBUS_VOUT_SENSORS_PER_PAGE 9 /* input, min, max, lcrit, | ||
38 | crit, lowest, highest, avg, | ||
39 | reset */ | ||
40 | #define PMBUS_IOUT_SENSORS_PER_PAGE 8 /* input, min, max, crit, | ||
41 | lowest, highest, avg, | ||
42 | reset */ | ||
43 | #define PMBUS_POUT_SENSORS_PER_PAGE 7 /* input, cap, max, crit, | ||
44 | * highest, avg, reset | ||
45 | */ | ||
46 | #define PMBUS_MAX_SENSORS_PER_FAN 1 /* input */ | ||
47 | #define PMBUS_MAX_SENSORS_PER_TEMP 9 /* input, min, max, lcrit, | ||
48 | * crit, lowest, highest, avg, | ||
49 | * reset | ||
50 | */ | ||
51 | |||
52 | #define PMBUS_MAX_INPUT_BOOLEANS 7 /* v: min_alarm, max_alarm, | ||
53 | lcrit_alarm, crit_alarm; | ||
54 | c: alarm, crit_alarm; | ||
55 | p: crit_alarm */ | ||
56 | #define PMBUS_VOUT_BOOLEANS_PER_PAGE 4 /* min_alarm, max_alarm, | ||
57 | lcrit_alarm, crit_alarm */ | ||
58 | #define PMBUS_IOUT_BOOLEANS_PER_PAGE 3 /* alarm, lcrit_alarm, | ||
59 | crit_alarm */ | ||
60 | #define PMBUS_POUT_BOOLEANS_PER_PAGE 3 /* cap_alarm, alarm, crit_alarm | ||
61 | */ | ||
62 | #define PMBUS_MAX_BOOLEANS_PER_FAN 2 /* alarm, fault */ | ||
63 | #define PMBUS_MAX_BOOLEANS_PER_TEMP 4 /* min_alarm, max_alarm, | ||
64 | lcrit_alarm, crit_alarm */ | ||
65 | |||
66 | #define PMBUS_MAX_INPUT_LABELS 4 /* vin, vcap, iin, pin */ | ||
67 | 38 | ||
68 | /* | 39 | /* |
69 | * status, status_vout, status_iout, status_fans, status_fan34, and status_temp | 40 | * status, status_vout, status_iout, status_fans, status_fan34, and status_temp |
@@ -127,7 +98,6 @@ struct pmbus_data { | |||
127 | 98 | ||
128 | int max_attributes; | 99 | int max_attributes; |
129 | int num_attributes; | 100 | int num_attributes; |
130 | struct attribute **attributes; | ||
131 | struct attribute_group group; | 101 | struct attribute_group group; |
132 | 102 | ||
133 | struct pmbus_sensor *sensors; | 103 | struct pmbus_sensor *sensors; |
@@ -790,6 +760,22 @@ static ssize_t pmbus_show_label(struct device *dev, | |||
790 | return snprintf(buf, PAGE_SIZE, "%s\n", label->label); | 760 | return snprintf(buf, PAGE_SIZE, "%s\n", label->label); |
791 | } | 761 | } |
792 | 762 | ||
763 | static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr) | ||
764 | { | ||
765 | if (data->num_attributes >= data->max_attributes - 1) { | ||
766 | data->max_attributes += PMBUS_ATTR_ALLOC_SIZE; | ||
767 | data->group.attrs = krealloc(data->group.attrs, | ||
768 | sizeof(struct attribute *) * | ||
769 | data->max_attributes, GFP_KERNEL); | ||
770 | if (data->group.attrs == NULL) | ||
771 | return -ENOMEM; | ||
772 | } | ||
773 | |||
774 | data->group.attrs[data->num_attributes++] = attr; | ||
775 | data->group.attrs[data->num_attributes] = NULL; | ||
776 | return 0; | ||
777 | } | ||
778 | |||
793 | static void pmbus_dev_attr_init(struct device_attribute *dev_attr, | 779 | static void pmbus_dev_attr_init(struct device_attribute *dev_attr, |
794 | const char *name, | 780 | const char *name, |
795 | umode_t mode, | 781 | umode_t mode, |
@@ -831,8 +817,6 @@ static int pmbus_add_boolean(struct pmbus_data *data, | |||
831 | struct pmbus_boolean *boolean; | 817 | struct pmbus_boolean *boolean; |
832 | struct sensor_device_attribute *a; | 818 | struct sensor_device_attribute *a; |
833 | 819 | ||
834 | BUG_ON(data->num_attributes >= data->max_attributes); | ||
835 | |||
836 | boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL); | 820 | boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL); |
837 | if (!boolean) | 821 | if (!boolean) |
838 | return -ENOMEM; | 822 | return -ENOMEM; |
@@ -845,9 +829,8 @@ static int pmbus_add_boolean(struct pmbus_data *data, | |||
845 | boolean->s2 = s2; | 829 | boolean->s2 = s2; |
846 | pmbus_attr_init(a, boolean->name, S_IRUGO, pmbus_show_boolean, NULL, | 830 | pmbus_attr_init(a, boolean->name, S_IRUGO, pmbus_show_boolean, NULL, |
847 | (reg << 8) | mask); | 831 | (reg << 8) | mask); |
848 | data->attributes[data->num_attributes++] = &a->dev_attr.attr; | ||
849 | 832 | ||
850 | return 0; | 833 | return pmbus_add_attribute(data, &a->dev_attr.attr); |
851 | } | 834 | } |
852 | 835 | ||
853 | static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, | 836 | static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, |
@@ -859,8 +842,6 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, | |||
859 | struct pmbus_sensor *sensor; | 842 | struct pmbus_sensor *sensor; |
860 | struct device_attribute *a; | 843 | struct device_attribute *a; |
861 | 844 | ||
862 | BUG_ON(data->num_attributes >= data->max_attributes); | ||
863 | |||
864 | sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL); | 845 | sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL); |
865 | if (!sensor) | 846 | if (!sensor) |
866 | return NULL; | 847 | return NULL; |
@@ -876,7 +857,9 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, | |||
876 | readonly ? S_IRUGO : S_IRUGO | S_IWUSR, | 857 | readonly ? S_IRUGO : S_IRUGO | S_IWUSR, |
877 | pmbus_show_sensor, pmbus_set_sensor); | 858 | pmbus_show_sensor, pmbus_set_sensor); |
878 | 859 | ||
879 | data->attributes[data->num_attributes++] = &a->attr; | 860 | if (pmbus_add_attribute(data, &a->attr)) |
861 | return NULL; | ||
862 | |||
880 | sensor->next = data->sensors; | 863 | sensor->next = data->sensors; |
881 | data->sensors = sensor; | 864 | data->sensors = sensor; |
882 | 865 | ||
@@ -890,8 +873,6 @@ static int pmbus_add_label(struct pmbus_data *data, | |||
890 | struct pmbus_label *label; | 873 | struct pmbus_label *label; |
891 | struct device_attribute *a; | 874 | struct device_attribute *a; |
892 | 875 | ||
893 | BUG_ON(data->num_attributes >= data->max_attributes); | ||
894 | |||
895 | label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL); | 876 | label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL); |
896 | if (!label) | 877 | if (!label) |
897 | return -ENOMEM; | 878 | return -ENOMEM; |
@@ -906,62 +887,7 @@ static int pmbus_add_label(struct pmbus_data *data, | |||
906 | index); | 887 | index); |
907 | 888 | ||
908 | pmbus_dev_attr_init(a, label->name, S_IRUGO, pmbus_show_label, NULL); | 889 | pmbus_dev_attr_init(a, label->name, S_IRUGO, pmbus_show_label, NULL); |
909 | data->attributes[data->num_attributes++] = &a->attr; | 890 | return pmbus_add_attribute(data, &a->attr); |
910 | return 0; | ||
911 | } | ||
912 | |||
913 | /* | ||
914 | * Determine maximum number of sensors, booleans, and labels. | ||
915 | * To keep things simple, only make a rough high estimate. | ||
916 | */ | ||
917 | static void pmbus_find_max_attr(struct i2c_client *client, | ||
918 | struct pmbus_data *data) | ||
919 | { | ||
920 | const struct pmbus_driver_info *info = data->info; | ||
921 | int page, max_sensors, max_booleans, max_labels; | ||
922 | |||
923 | max_sensors = PMBUS_MAX_INPUT_SENSORS; | ||
924 | max_booleans = PMBUS_MAX_INPUT_BOOLEANS; | ||
925 | max_labels = PMBUS_MAX_INPUT_LABELS; | ||
926 | |||
927 | for (page = 0; page < info->pages; page++) { | ||
928 | if (info->func[page] & PMBUS_HAVE_VOUT) { | ||
929 | max_sensors += PMBUS_VOUT_SENSORS_PER_PAGE; | ||
930 | max_booleans += PMBUS_VOUT_BOOLEANS_PER_PAGE; | ||
931 | max_labels++; | ||
932 | } | ||
933 | if (info->func[page] & PMBUS_HAVE_IOUT) { | ||
934 | max_sensors += PMBUS_IOUT_SENSORS_PER_PAGE; | ||
935 | max_booleans += PMBUS_IOUT_BOOLEANS_PER_PAGE; | ||
936 | max_labels++; | ||
937 | } | ||
938 | if (info->func[page] & PMBUS_HAVE_POUT) { | ||
939 | max_sensors += PMBUS_POUT_SENSORS_PER_PAGE; | ||
940 | max_booleans += PMBUS_POUT_BOOLEANS_PER_PAGE; | ||
941 | max_labels++; | ||
942 | } | ||
943 | if (info->func[page] & PMBUS_HAVE_FAN12) { | ||
944 | max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN; | ||
945 | max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN; | ||
946 | } | ||
947 | if (info->func[page] & PMBUS_HAVE_FAN34) { | ||
948 | max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN; | ||
949 | max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN; | ||
950 | } | ||
951 | if (info->func[page] & PMBUS_HAVE_TEMP) { | ||
952 | max_sensors += PMBUS_MAX_SENSORS_PER_TEMP; | ||
953 | max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP; | ||
954 | } | ||
955 | if (info->func[page] & PMBUS_HAVE_TEMP2) { | ||
956 | max_sensors += PMBUS_MAX_SENSORS_PER_TEMP; | ||
957 | max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP; | ||
958 | } | ||
959 | if (info->func[page] & PMBUS_HAVE_TEMP3) { | ||
960 | max_sensors += PMBUS_MAX_SENSORS_PER_TEMP; | ||
961 | max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP; | ||
962 | } | ||
963 | } | ||
964 | data->max_attributes = max_sensors + max_booleans + max_labels; | ||
965 | } | 891 | } |
966 | 892 | ||
967 | /* | 893 | /* |
@@ -1709,8 +1635,6 @@ static int pmbus_identify_common(struct i2c_client *client, | |||
1709 | } | 1635 | } |
1710 | } | 1636 | } |
1711 | 1637 | ||
1712 | /* Determine maximum number of sensors, booleans, and labels */ | ||
1713 | pmbus_find_max_attr(client, data); | ||
1714 | pmbus_clear_fault_page(client, 0); | 1638 | pmbus_clear_fault_page(client, 0); |
1715 | return 0; | 1639 | return 0; |
1716 | } | 1640 | } |
@@ -1770,14 +1694,9 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, | |||
1770 | return ret; | 1694 | return ret; |
1771 | } | 1695 | } |
1772 | 1696 | ||
1773 | data->attributes = devm_kzalloc(dev, sizeof(struct attribute *) | ||
1774 | * data->max_attributes, GFP_KERNEL); | ||
1775 | if (!data->attributes) | ||
1776 | return -ENOMEM; | ||
1777 | |||
1778 | ret = pmbus_find_attributes(client, data); | 1697 | ret = pmbus_find_attributes(client, data); |
1779 | if (ret) | 1698 | if (ret) |
1780 | return ret; | 1699 | goto out_kfree; |
1781 | 1700 | ||
1782 | /* | 1701 | /* |
1783 | * If there are no attributes, something is wrong. | 1702 | * If there are no attributes, something is wrong. |
@@ -1785,15 +1704,15 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, | |||
1785 | */ | 1704 | */ |
1786 | if (!data->num_attributes) { | 1705 | if (!data->num_attributes) { |
1787 | dev_err(dev, "No attributes found\n"); | 1706 | dev_err(dev, "No attributes found\n"); |
1788 | return -ENODEV; | 1707 | ret = -ENODEV; |
1708 | goto out_kfree; | ||
1789 | } | 1709 | } |
1790 | 1710 | ||
1791 | /* Register sysfs hooks */ | 1711 | /* Register sysfs hooks */ |
1792 | data->group.attrs = data->attributes; | ||
1793 | ret = sysfs_create_group(&dev->kobj, &data->group); | 1712 | ret = sysfs_create_group(&dev->kobj, &data->group); |
1794 | if (ret) { | 1713 | if (ret) { |
1795 | dev_err(dev, "Failed to create sysfs entries\n"); | 1714 | dev_err(dev, "Failed to create sysfs entries\n"); |
1796 | return ret; | 1715 | goto out_kfree; |
1797 | } | 1716 | } |
1798 | data->hwmon_dev = hwmon_device_register(dev); | 1717 | data->hwmon_dev = hwmon_device_register(dev); |
1799 | if (IS_ERR(data->hwmon_dev)) { | 1718 | if (IS_ERR(data->hwmon_dev)) { |
@@ -1805,6 +1724,8 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, | |||
1805 | 1724 | ||
1806 | out_hwmon_device_register: | 1725 | out_hwmon_device_register: |
1807 | sysfs_remove_group(&dev->kobj, &data->group); | 1726 | sysfs_remove_group(&dev->kobj, &data->group); |
1727 | out_kfree: | ||
1728 | kfree(data->group.attrs); | ||
1808 | return ret; | 1729 | return ret; |
1809 | } | 1730 | } |
1810 | EXPORT_SYMBOL_GPL(pmbus_do_probe); | 1731 | EXPORT_SYMBOL_GPL(pmbus_do_probe); |
@@ -1814,6 +1735,7 @@ int pmbus_do_remove(struct i2c_client *client) | |||
1814 | struct pmbus_data *data = i2c_get_clientdata(client); | 1735 | struct pmbus_data *data = i2c_get_clientdata(client); |
1815 | hwmon_device_unregister(data->hwmon_dev); | 1736 | hwmon_device_unregister(data->hwmon_dev); |
1816 | sysfs_remove_group(&client->dev.kobj, &data->group); | 1737 | sysfs_remove_group(&client->dev.kobj, &data->group); |
1738 | kfree(data->group.attrs); | ||
1817 | return 0; | 1739 | return 0; |
1818 | } | 1740 | } |
1819 | EXPORT_SYMBOL_GPL(pmbus_do_remove); | 1741 | EXPORT_SYMBOL_GPL(pmbus_do_remove); |