Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hwmon: iio: Add labels from IIO channels

Add labels from IIO channels to our channels. This allows userspace to
display more meaningful names instead of "in0" or "temp5".

Although lm-sensors gracefully handles errors when reading channel
labels, the ABI says the label attribute

> Should only be created if the driver has hints about what this voltage
> channel is being used for, and user-space doesn't.

Therefore, we test to see if the channel has a label before
creating the attribute.

Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Link: https://patch.msgid.link/20240624174601.1527244-3-sean.anderson@linux.dev
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Sean Anderson and committed by
Jonathan Cameron
440db407 0214b27f

+40 -5
+40 -5
drivers/hwmon/iio_hwmon.c
··· 33 33 struct attribute **attrs; 34 34 }; 35 35 36 + static ssize_t iio_hwmon_read_label(struct device *dev, 37 + struct device_attribute *attr, 38 + char *buf) 39 + { 40 + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); 41 + struct iio_hwmon_state *state = dev_get_drvdata(dev); 42 + struct iio_channel *chan = &state->channels[sattr->index]; 43 + 44 + return iio_read_channel_label(chan, buf); 45 + } 46 + 36 47 /* 37 48 * Assumes that IIO and hwmon operate in the same base units. 38 49 * This is supposed to be true, but needs verification for ··· 79 68 struct device *dev = &pdev->dev; 80 69 struct iio_hwmon_state *st; 81 70 struct sensor_device_attribute *a; 82 - int ret, i; 71 + int ret, i, attr = 0; 83 72 int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1, power_i = 1; 84 73 enum iio_chan_type type; 85 74 struct iio_channel *channels; 86 75 struct device *hwmon_dev; 87 76 char *sname; 77 + void *buf; 88 78 89 79 channels = devm_iio_channel_get_all(dev); 90 80 if (IS_ERR(channels)) { ··· 97 85 } 98 86 99 87 st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); 100 - if (st == NULL) 88 + buf = (void *)devm_get_free_pages(dev, GFP_KERNEL, 0); 89 + if (!st || !buf) 101 90 return -ENOMEM; 102 91 103 92 st->channels = channels; 104 93 105 - /* count how many attributes we have */ 94 + /* count how many channels we have */ 106 95 while (st->channels[st->num_channels].indio_dev) 107 96 st->num_channels++; 108 97 109 98 st->attrs = devm_kcalloc(dev, 110 - st->num_channels + 1, sizeof(*st->attrs), 99 + 2 * st->num_channels + 1, sizeof(*st->attrs), 111 100 GFP_KERNEL); 112 101 if (st->attrs == NULL) 113 102 return -ENOMEM; ··· 160 147 a->dev_attr.show = iio_hwmon_read_val; 161 148 a->dev_attr.attr.mode = 0444; 162 149 a->index = i; 163 - st->attrs[i] = &a->dev_attr.attr; 150 + st->attrs[attr++] = &a->dev_attr.attr; 151 + 152 + /* Let's see if we have a label... */ 153 + if (iio_read_channel_label(&st->channels[i], buf) < 0) 154 + continue; 155 + 156 + a = devm_kzalloc(dev, sizeof(*a), GFP_KERNEL); 157 + if (a == NULL) 158 + return -ENOMEM; 159 + 160 + sysfs_attr_init(&a->dev_attr.attr); 161 + a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, 162 + "%s%d_label", 163 + prefix, n); 164 + if (!a->dev_attr.attr.name) 165 + return -ENOMEM; 166 + 167 + a->dev_attr.show = iio_hwmon_read_label; 168 + a->dev_attr.attr.mode = 0444; 169 + a->index = i; 170 + st->attrs[attr++] = &a->dev_attr.attr; 164 171 } 172 + 173 + devm_free_pages(dev, (unsigned long)buf); 165 174 166 175 st->attr_group.attrs = st->attrs; 167 176 st->groups[0] = &st->attr_group;