]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/hwmon/hwmon.c
Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64...
[mirror_ubuntu-bionic-kernel.git] / drivers / hwmon / hwmon.c
index a74c075a30ec49608308ddd45715f1addc104c84..3932f9276c074d92b7028b32c29e36c6a5aa9738 100644 (file)
@@ -38,12 +38,15 @@ struct hwmon_device {
 
 #define to_hwmon_device(d) container_of(d, struct hwmon_device, dev)
 
+#define MAX_SYSFS_ATTR_NAME_LENGTH     32
+
 struct hwmon_device_attribute {
        struct device_attribute dev_attr;
        const struct hwmon_ops *ops;
        enum hwmon_sensor_types type;
        u32 attr;
        int index;
+       char name[MAX_SYSFS_ATTR_NAME_LENGTH];
 };
 
 #define to_hwmon_attr(d) \
@@ -178,6 +181,22 @@ static ssize_t hwmon_attr_show(struct device *dev,
        return sprintf(buf, "%ld\n", val);
 }
 
+static ssize_t hwmon_attr_show_string(struct device *dev,
+                                     struct device_attribute *devattr,
+                                     char *buf)
+{
+       struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr);
+       char *s;
+       int ret;
+
+       ret = hattr->ops->read_string(dev, hattr->type, hattr->attr,
+                                     hattr->index, &s);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%s\n", s);
+}
+
 static ssize_t hwmon_attr_store(struct device *dev,
                                struct device_attribute *devattr,
                                const char *buf, size_t count)
@@ -205,6 +224,17 @@ static int hwmon_attr_base(enum hwmon_sensor_types type)
        return 1;
 }
 
+static bool is_string_attr(enum hwmon_sensor_types type, u32 attr)
+{
+       return (type == hwmon_temp && attr == hwmon_temp_label) ||
+              (type == hwmon_in && attr == hwmon_in_label) ||
+              (type == hwmon_curr && attr == hwmon_curr_label) ||
+              (type == hwmon_power && attr == hwmon_power_label) ||
+              (type == hwmon_energy && attr == hwmon_energy_label) ||
+              (type == hwmon_humidity && attr == hwmon_humidity_label) ||
+              (type == hwmon_fan && attr == hwmon_fan_label);
+}
+
 static struct attribute *hwmon_genattr(struct device *dev,
                                       const void *drvdata,
                                       enum hwmon_sensor_types type,
@@ -218,6 +248,7 @@ static struct attribute *hwmon_genattr(struct device *dev,
        struct attribute *a;
        umode_t mode;
        char *name;
+       bool is_string = is_string_attr(type, attr);
 
        /* The attribute is invisible if there is no template string */
        if (!template)
@@ -227,32 +258,31 @@ static struct attribute *hwmon_genattr(struct device *dev,
        if (!mode)
                return ERR_PTR(-ENOENT);
 
-       if ((mode & S_IRUGO) && !ops->read)
+       if ((mode & S_IRUGO) && ((is_string && !ops->read_string) ||
+                                (!is_string && !ops->read)))
                return ERR_PTR(-EINVAL);
        if ((mode & S_IWUGO) && !ops->write)
                return ERR_PTR(-EINVAL);
 
+       hattr = devm_kzalloc(dev, sizeof(*hattr), GFP_KERNEL);
+       if (!hattr)
+               return ERR_PTR(-ENOMEM);
+
        if (type == hwmon_chip) {
                name = (char *)template;
        } else {
-               name = devm_kzalloc(dev, strlen(template) + 16, GFP_KERNEL);
-               if (!name)
-                       return ERR_PTR(-ENOMEM);
-               scnprintf(name, strlen(template) + 16, template,
+               scnprintf(hattr->name, sizeof(hattr->name), template,
                          index + hwmon_attr_base(type));
+               name = hattr->name;
        }
 
-       hattr = devm_kzalloc(dev, sizeof(*hattr), GFP_KERNEL);
-       if (!hattr)
-               return ERR_PTR(-ENOMEM);
-
        hattr->type = type;
        hattr->attr = attr;
        hattr->index = index;
        hattr->ops = ops;
 
        dattr = &hattr->dev_attr;
-       dattr->show = hwmon_attr_show;
+       dattr->show = is_string ? hwmon_attr_show_string : hwmon_attr_show;
        dattr->store = hwmon_attr_store;
 
        a = &dattr->attr;
@@ -263,7 +293,11 @@ static struct attribute *hwmon_genattr(struct device *dev,
        return a;
 }
 
-static const char * const hwmon_chip_attr_templates[] = {
+/*
+ * Chip attributes are not attribute templates but actual sysfs attributes.
+ * See hwmon_genattr() for special handling.
+ */
+static const char * const hwmon_chip_attrs[] = {
        [hwmon_chip_temp_reset_history] = "temp_reset_history",
        [hwmon_chip_in_reset_history] = "in_reset_history",
        [hwmon_chip_curr_reset_history] = "curr_reset_history",
@@ -400,7 +434,7 @@ static const char * const hwmon_pwm_attr_templates[] = {
 };
 
 static const char * const *__templates[] = {
-       [hwmon_chip] = hwmon_chip_attr_templates,
+       [hwmon_chip] = hwmon_chip_attrs,
        [hwmon_temp] = hwmon_temp_attr_templates,
        [hwmon_in] = hwmon_in_attr_templates,
        [hwmon_curr] = hwmon_curr_attr_templates,
@@ -412,7 +446,7 @@ static const char * const *__templates[] = {
 };
 
 static const int __templates_size[] = {
-       [hwmon_chip] = ARRAY_SIZE(hwmon_chip_attr_templates),
+       [hwmon_chip] = ARRAY_SIZE(hwmon_chip_attrs),
        [hwmon_temp] = ARRAY_SIZE(hwmon_temp_attr_templates),
        [hwmon_in] = ARRAY_SIZE(hwmon_in_attr_templates),
        [hwmon_curr] = ARRAY_SIZE(hwmon_curr_attr_templates),
@@ -526,9 +560,9 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
 
        hdev = &hwdev->dev;
 
-       if (chip && chip->ops->is_visible) {
+       if (chip) {
                struct attribute **attrs;
-               int ngroups = 2;
+               int ngroups = 2; /* terminating NULL plus &hwdev->groups */
 
                if (groups)
                        for (i = 0; groups[i]; i++)
@@ -572,7 +606,7 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
        if (err)
                goto free_hwmon;
 
-       if (chip && chip->ops->is_visible && chip->ops->read &&
+       if (chip && chip->ops->read &&
            chip->info[0]->type == hwmon_chip &&
            (chip->info[0]->config[0] & HWMON_C_REGISTER_TZ)) {
                const struct hwmon_channel_info **info = chip->info;
@@ -626,8 +660,8 @@ EXPORT_SYMBOL_GPL(hwmon_device_register_with_groups);
  * @dev: the parent device
  * @name: hwmon name attribute
  * @drvdata: driver data to attach to created device
- * @info: Pointer to hwmon chip information
- * @groups - pointer to list of driver specific attribute groups
+ * @info: pointer to hwmon chip information
+ * @extra_groups: pointer to list of additional non-standard attribute groups
  *
  * hwmon_device_unregister() must be called when the device is no
  * longer needed.
@@ -638,12 +672,12 @@ struct device *
 hwmon_device_register_with_info(struct device *dev, const char *name,
                                void *drvdata,
                                const struct hwmon_chip_info *chip,
-                               const struct attribute_group **groups)
+                               const struct attribute_group **extra_groups)
 {
-       if (chip && (!chip->ops || !chip->info))
+       if (chip && (!chip->ops || !chip->ops->is_visible || !chip->info))
                return ERR_PTR(-EINVAL);
 
-       return __hwmon_device_register(dev, name, drvdata, chip, groups);
+       return __hwmon_device_register(dev, name, drvdata, chip, extra_groups);
 }
 EXPORT_SYMBOL_GPL(hwmon_device_register_with_info);
 
@@ -658,6 +692,9 @@ EXPORT_SYMBOL_GPL(hwmon_device_register_with_info);
  */
 struct device *hwmon_device_register(struct device *dev)
 {
+       dev_warn(dev,
+                "hwmon_device_register() is deprecated. Please convert the driver to use hwmon_device_register_with_info().\n");
+
        return hwmon_device_register_with_groups(dev, NULL, NULL, NULL);
 }
 EXPORT_SYMBOL_GPL(hwmon_device_register);