summaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/hwmon.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/hwmon.c')
-rw-r--r--drivers/hwmon/hwmon.c85
1 files changed, 62 insertions, 23 deletions
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index adae6848ffb2..3932f9276c07 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -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++)
@@ -536,8 +570,10 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
hwdev->groups = devm_kcalloc(dev, ngroups, sizeof(*groups),
GFP_KERNEL);
- if (!hwdev->groups)
- return ERR_PTR(-ENOMEM);
+ if (!hwdev->groups) {
+ err = -ENOMEM;
+ goto free_hwmon;
+ }
attrs = __hwmon_create_attrs(dev, drvdata, chip);
if (IS_ERR(attrs)) {
@@ -570,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;
@@ -624,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.
@@ -636,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);
@@ -656,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);