Merge tag 'for-5.8-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
[linux-2.6-microblaze.git] / drivers / power / supply / power_supply_hwmon.c
index 75cf861..7fe4b6b 100644 (file)
@@ -13,6 +13,11 @@ struct power_supply_hwmon {
        unsigned long *props;
 };
 
+static const char *const ps_temp_label[] = {
+       "temp",
+       "ambient temp",
+};
+
 static int power_supply_hwmon_in_to_property(u32 attr)
 {
        switch (attr) {
@@ -98,6 +103,39 @@ static bool power_supply_hwmon_is_a_label(enum hwmon_sensor_types type,
        return type == hwmon_temp && attr == hwmon_temp_label;
 }
 
+struct hwmon_type_attr_list {
+       const u32 *attrs;
+       size_t n_attrs;
+};
+
+static const u32 ps_temp_attrs[] = {
+       hwmon_temp_input,
+       hwmon_temp_min, hwmon_temp_max,
+       hwmon_temp_min_alarm, hwmon_temp_max_alarm,
+};
+
+static const struct hwmon_type_attr_list ps_type_attrs[hwmon_max] = {
+       [hwmon_temp] = { ps_temp_attrs, ARRAY_SIZE(ps_temp_attrs) },
+};
+
+static bool power_supply_hwmon_has_input(
+       const struct power_supply_hwmon *psyhw,
+       enum hwmon_sensor_types type, int channel)
+{
+       const struct hwmon_type_attr_list *attr_list = &ps_type_attrs[type];
+       size_t i;
+
+       for (i = 0; i < attr_list->n_attrs; ++i) {
+               int prop = power_supply_hwmon_to_property(type,
+                       attr_list->attrs[i], channel);
+
+               if (prop >= 0 && test_bit(prop, psyhw->props))
+                       return true;
+       }
+
+       return false;
+}
+
 static bool power_supply_hwmon_is_writable(enum hwmon_sensor_types type,
                                           u32 attr)
 {
@@ -124,9 +162,12 @@ static umode_t power_supply_hwmon_is_visible(const void *data,
        const struct power_supply_hwmon *psyhw = data;
        int prop;
 
-
-       if (power_supply_hwmon_is_a_label(type, attr))
-               return 0444;
+       if (power_supply_hwmon_is_a_label(type, attr)) {
+               if (power_supply_hwmon_has_input(psyhw, type, channel))
+                       return 0444;
+               else
+                       return 0;
+       }
 
        prop = power_supply_hwmon_to_property(type, attr, channel);
        if (prop < 0 || !test_bit(prop, psyhw->props))
@@ -144,7 +185,20 @@ static int power_supply_hwmon_read_string(struct device *dev,
                                          u32 attr, int channel,
                                          const char **str)
 {
-       *str = channel ? "temp" : "temp ambient";
+       switch (type) {
+       case hwmon_temp:
+               *str = ps_temp_label[channel];
+               break;
+       default:
+               /* unreachable, but see:
+                * gcc bug #51513 [1] and clang bug #978 [2]
+                *
+                * [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51513
+                * [2] https://github.com/ClangBuiltLinux/linux/issues/978
+                */
+               break;
+       }
+
        return 0;
 }
 
@@ -304,7 +358,7 @@ int power_supply_add_hwmon_sysfs(struct power_supply *psy)
                goto error;
        }
 
-       ret = devm_add_action(dev, power_supply_hwmon_bitmap_free,
+       ret = devm_add_action_or_reset(dev, power_supply_hwmon_bitmap_free,
                              psyhw->props);
        if (ret)
                goto error;