^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * This file defines the sysfs class "hwmon", for use by sensors drivers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/gfp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/hwmon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/idr.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/thermal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define CREATE_TRACE_POINTS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <trace/events/hwmon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define HWMON_ID_PREFIX "hwmon"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct hwmon_device {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct device dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) const struct hwmon_chip_info *chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct list_head tzdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct attribute_group group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) const struct attribute_group **groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define to_hwmon_device(d) container_of(d, struct hwmon_device, dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define MAX_SYSFS_ATTR_NAME_LENGTH 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct hwmon_device_attribute {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct device_attribute dev_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) const struct hwmon_ops *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) enum hwmon_sensor_types type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) u32 attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) char name[MAX_SYSFS_ATTR_NAME_LENGTH];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define to_hwmon_attr(d) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) container_of(d, struct hwmon_device_attribute, dev_attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define to_dev_attr(a) container_of(a, struct device_attribute, attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * Thermal zone information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct hwmon_thermal_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct list_head node; /* hwmon tzdata list entry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct device *dev; /* Reference to hwmon device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) int index; /* sensor index */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct thermal_zone_device *tzd;/* thermal zone device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) name_show(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return sprintf(buf, "%s\n", to_hwmon_device(dev)->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static DEVICE_ATTR_RO(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static struct attribute *hwmon_dev_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) &dev_attr_name.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static umode_t hwmon_dev_name_is_visible(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct attribute *attr, int n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct device *dev = container_of(kobj, struct device, kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (to_hwmon_device(dev)->name == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return attr->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static const struct attribute_group hwmon_dev_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) .attrs = hwmon_dev_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) .is_visible = hwmon_dev_name_is_visible,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static const struct attribute_group *hwmon_dev_attr_groups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) &hwmon_dev_attr_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static void hwmon_free_attrs(struct attribute **attrs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) for (i = 0; attrs[i]; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) struct device_attribute *dattr = to_dev_attr(attrs[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct hwmon_device_attribute *hattr = to_hwmon_attr(dattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) kfree(hattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) kfree(attrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static void hwmon_dev_release(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct hwmon_device *hwdev = to_hwmon_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (hwdev->group.attrs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) hwmon_free_attrs(hwdev->group.attrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) kfree(hwdev->groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) kfree(hwdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static struct class hwmon_class = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) .name = "hwmon",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) .dev_groups = hwmon_dev_attr_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) .dev_release = hwmon_dev_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static DEFINE_IDA(hwmon_ida);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) /* Thermal zone handling */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * The complex conditional is necessary to avoid a cyclic dependency
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * between hwmon and thermal_sys modules.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) #ifdef CONFIG_THERMAL_OF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) static int hwmon_thermal_get_temp(void *data, int *temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct hwmon_thermal_data *tdata = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) struct hwmon_device *hwdev = to_hwmon_device(tdata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) long t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) ret = hwdev->chip->ops->read(tdata->dev, hwmon_temp, hwmon_temp_input,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) tdata->index, &t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) *temp = t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) static const struct thermal_zone_of_device_ops hwmon_thermal_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) .get_temp = hwmon_thermal_get_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static void hwmon_thermal_remove_sensor(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) list_del(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) static int hwmon_thermal_add_sensor(struct device *dev, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) struct hwmon_device *hwdev = to_hwmon_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) struct hwmon_thermal_data *tdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) struct thermal_zone_device *tzd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) tdata = devm_kzalloc(dev, sizeof(*tdata), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (!tdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) tdata->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) tdata->index = index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) tzd = devm_thermal_zone_of_sensor_register(dev, index, tdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) &hwmon_thermal_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (IS_ERR(tzd)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (PTR_ERR(tzd) != -ENODEV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) return PTR_ERR(tzd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) dev_info(dev, "temp%d_input not attached to any thermal zone\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) index + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) devm_kfree(dev, tdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) err = devm_add_action(dev, hwmon_thermal_remove_sensor, &tdata->node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) tdata->tzd = tzd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) list_add(&tdata->node, &hwdev->tzdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) static int hwmon_thermal_register_sensors(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct hwmon_device *hwdev = to_hwmon_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) const struct hwmon_chip_info *chip = hwdev->chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) const struct hwmon_channel_info **info = chip->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) void *drvdata = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) for (i = 1; info[i]; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) int j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (info[i]->type != hwmon_temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) for (j = 0; info[i]->config[j]; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (!(info[i]->config[j] & HWMON_T_INPUT) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) !chip->ops->is_visible(drvdata, hwmon_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) hwmon_temp_input, j))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) err = hwmon_thermal_add_sensor(dev, j);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) static void hwmon_thermal_notify(struct device *dev, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) struct hwmon_device *hwdev = to_hwmon_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) struct hwmon_thermal_data *tzdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) list_for_each_entry(tzdata, &hwdev->tzdata, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (tzdata->index == index) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) thermal_zone_device_update(tzdata->tzd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) THERMAL_EVENT_UNSPECIFIED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) static int hwmon_thermal_register_sensors(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static void hwmon_thermal_notify(struct device *dev, int index) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) #endif /* IS_REACHABLE(CONFIG_THERMAL) && ... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) static int hwmon_attr_base(enum hwmon_sensor_types type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) if (type == hwmon_in || type == hwmon_intrusion)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) /* sysfs attribute management */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) static ssize_t hwmon_attr_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) struct device_attribute *devattr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) ret = hattr->ops->read(dev, hattr->type, hattr->attr, hattr->index,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) trace_hwmon_attr_show(hattr->index + hwmon_attr_base(hattr->type),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) hattr->name, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) return sprintf(buf, "%ld\n", val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) static ssize_t hwmon_attr_show_string(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) struct device_attribute *devattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) enum hwmon_sensor_types type = hattr->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) const char *s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) ret = hattr->ops->read_string(dev, hattr->type, hattr->attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) hattr->index, &s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) trace_hwmon_attr_show_string(hattr->index + hwmon_attr_base(type),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) hattr->name, s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) return sprintf(buf, "%s\n", s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) static ssize_t hwmon_attr_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) struct device_attribute *devattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) ret = kstrtol(buf, 10, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) ret = hattr->ops->write(dev, hattr->type, hattr->attr, hattr->index,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) trace_hwmon_attr_store(hattr->index + hwmon_attr_base(hattr->type),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) hattr->name, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) static bool is_string_attr(enum hwmon_sensor_types type, u32 attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) return (type == hwmon_temp && attr == hwmon_temp_label) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) (type == hwmon_in && attr == hwmon_in_label) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) (type == hwmon_curr && attr == hwmon_curr_label) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) (type == hwmon_power && attr == hwmon_power_label) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) (type == hwmon_energy && attr == hwmon_energy_label) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) (type == hwmon_humidity && attr == hwmon_humidity_label) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) (type == hwmon_fan && attr == hwmon_fan_label);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) static struct attribute *hwmon_genattr(const void *drvdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) enum hwmon_sensor_types type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) u32 attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) int index,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) const char *template,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) const struct hwmon_ops *ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) struct hwmon_device_attribute *hattr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) struct device_attribute *dattr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) struct attribute *a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) umode_t mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) bool is_string = is_string_attr(type, attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) /* The attribute is invisible if there is no template string */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (!template)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) return ERR_PTR(-ENOENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) mode = ops->is_visible(drvdata, type, attr, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) if (!mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) return ERR_PTR(-ENOENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) if ((mode & 0444) && ((is_string && !ops->read_string) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) (!is_string && !ops->read)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) if ((mode & 0222) && !ops->write)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) hattr = kzalloc(sizeof(*hattr), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) if (!hattr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) if (type == hwmon_chip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) name = template;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) scnprintf(hattr->name, sizeof(hattr->name), template,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) index + hwmon_attr_base(type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) name = hattr->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) hattr->type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) hattr->attr = attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) hattr->index = index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) hattr->ops = ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) dattr = &hattr->dev_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) dattr->show = is_string ? hwmon_attr_show_string : hwmon_attr_show;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) dattr->store = hwmon_attr_store;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) a = &dattr->attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) sysfs_attr_init(a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) a->name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) a->mode = mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) return a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) * Chip attributes are not attribute templates but actual sysfs attributes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) * See hwmon_genattr() for special handling.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) static const char * const hwmon_chip_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) [hwmon_chip_temp_reset_history] = "temp_reset_history",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) [hwmon_chip_in_reset_history] = "in_reset_history",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) [hwmon_chip_curr_reset_history] = "curr_reset_history",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) [hwmon_chip_power_reset_history] = "power_reset_history",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) [hwmon_chip_update_interval] = "update_interval",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) [hwmon_chip_alarms] = "alarms",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) [hwmon_chip_samples] = "samples",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) [hwmon_chip_curr_samples] = "curr_samples",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) [hwmon_chip_in_samples] = "in_samples",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) [hwmon_chip_power_samples] = "power_samples",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) [hwmon_chip_temp_samples] = "temp_samples",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) static const char * const hwmon_temp_attr_templates[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) [hwmon_temp_enable] = "temp%d_enable",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) [hwmon_temp_input] = "temp%d_input",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) [hwmon_temp_type] = "temp%d_type",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) [hwmon_temp_lcrit] = "temp%d_lcrit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) [hwmon_temp_lcrit_hyst] = "temp%d_lcrit_hyst",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) [hwmon_temp_min] = "temp%d_min",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) [hwmon_temp_min_hyst] = "temp%d_min_hyst",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) [hwmon_temp_max] = "temp%d_max",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) [hwmon_temp_max_hyst] = "temp%d_max_hyst",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) [hwmon_temp_crit] = "temp%d_crit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) [hwmon_temp_crit_hyst] = "temp%d_crit_hyst",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) [hwmon_temp_emergency] = "temp%d_emergency",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) [hwmon_temp_emergency_hyst] = "temp%d_emergency_hyst",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) [hwmon_temp_alarm] = "temp%d_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) [hwmon_temp_lcrit_alarm] = "temp%d_lcrit_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) [hwmon_temp_min_alarm] = "temp%d_min_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) [hwmon_temp_max_alarm] = "temp%d_max_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) [hwmon_temp_crit_alarm] = "temp%d_crit_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) [hwmon_temp_emergency_alarm] = "temp%d_emergency_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) [hwmon_temp_fault] = "temp%d_fault",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) [hwmon_temp_offset] = "temp%d_offset",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) [hwmon_temp_label] = "temp%d_label",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) [hwmon_temp_lowest] = "temp%d_lowest",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) [hwmon_temp_highest] = "temp%d_highest",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) [hwmon_temp_reset_history] = "temp%d_reset_history",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) [hwmon_temp_rated_min] = "temp%d_rated_min",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) [hwmon_temp_rated_max] = "temp%d_rated_max",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) static const char * const hwmon_in_attr_templates[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) [hwmon_in_enable] = "in%d_enable",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) [hwmon_in_input] = "in%d_input",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) [hwmon_in_min] = "in%d_min",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) [hwmon_in_max] = "in%d_max",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) [hwmon_in_lcrit] = "in%d_lcrit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) [hwmon_in_crit] = "in%d_crit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) [hwmon_in_average] = "in%d_average",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) [hwmon_in_lowest] = "in%d_lowest",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) [hwmon_in_highest] = "in%d_highest",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) [hwmon_in_reset_history] = "in%d_reset_history",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) [hwmon_in_label] = "in%d_label",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) [hwmon_in_alarm] = "in%d_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) [hwmon_in_min_alarm] = "in%d_min_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) [hwmon_in_max_alarm] = "in%d_max_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) [hwmon_in_lcrit_alarm] = "in%d_lcrit_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) [hwmon_in_crit_alarm] = "in%d_crit_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) [hwmon_in_rated_min] = "in%d_rated_min",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) [hwmon_in_rated_max] = "in%d_rated_max",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) static const char * const hwmon_curr_attr_templates[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) [hwmon_curr_enable] = "curr%d_enable",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) [hwmon_curr_input] = "curr%d_input",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) [hwmon_curr_min] = "curr%d_min",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) [hwmon_curr_max] = "curr%d_max",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) [hwmon_curr_lcrit] = "curr%d_lcrit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) [hwmon_curr_crit] = "curr%d_crit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) [hwmon_curr_average] = "curr%d_average",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) [hwmon_curr_lowest] = "curr%d_lowest",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) [hwmon_curr_highest] = "curr%d_highest",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) [hwmon_curr_reset_history] = "curr%d_reset_history",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) [hwmon_curr_label] = "curr%d_label",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) [hwmon_curr_alarm] = "curr%d_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) [hwmon_curr_min_alarm] = "curr%d_min_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) [hwmon_curr_max_alarm] = "curr%d_max_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) [hwmon_curr_lcrit_alarm] = "curr%d_lcrit_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) [hwmon_curr_crit_alarm] = "curr%d_crit_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) [hwmon_curr_rated_min] = "curr%d_rated_min",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) [hwmon_curr_rated_max] = "curr%d_rated_max",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) static const char * const hwmon_power_attr_templates[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) [hwmon_power_enable] = "power%d_enable",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) [hwmon_power_average] = "power%d_average",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) [hwmon_power_average_interval] = "power%d_average_interval",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) [hwmon_power_average_interval_max] = "power%d_interval_max",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) [hwmon_power_average_interval_min] = "power%d_interval_min",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) [hwmon_power_average_highest] = "power%d_average_highest",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) [hwmon_power_average_lowest] = "power%d_average_lowest",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) [hwmon_power_average_max] = "power%d_average_max",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) [hwmon_power_average_min] = "power%d_average_min",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) [hwmon_power_input] = "power%d_input",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) [hwmon_power_input_highest] = "power%d_input_highest",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) [hwmon_power_input_lowest] = "power%d_input_lowest",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) [hwmon_power_reset_history] = "power%d_reset_history",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) [hwmon_power_accuracy] = "power%d_accuracy",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) [hwmon_power_cap] = "power%d_cap",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) [hwmon_power_cap_hyst] = "power%d_cap_hyst",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) [hwmon_power_cap_max] = "power%d_cap_max",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) [hwmon_power_cap_min] = "power%d_cap_min",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) [hwmon_power_min] = "power%d_min",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) [hwmon_power_max] = "power%d_max",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) [hwmon_power_lcrit] = "power%d_lcrit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) [hwmon_power_crit] = "power%d_crit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) [hwmon_power_label] = "power%d_label",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) [hwmon_power_alarm] = "power%d_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) [hwmon_power_cap_alarm] = "power%d_cap_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) [hwmon_power_min_alarm] = "power%d_min_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) [hwmon_power_max_alarm] = "power%d_max_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) [hwmon_power_lcrit_alarm] = "power%d_lcrit_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) [hwmon_power_crit_alarm] = "power%d_crit_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) [hwmon_power_rated_min] = "power%d_rated_min",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) [hwmon_power_rated_max] = "power%d_rated_max",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) static const char * const hwmon_energy_attr_templates[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) [hwmon_energy_enable] = "energy%d_enable",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) [hwmon_energy_input] = "energy%d_input",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) [hwmon_energy_label] = "energy%d_label",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) static const char * const hwmon_humidity_attr_templates[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) [hwmon_humidity_enable] = "humidity%d_enable",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) [hwmon_humidity_input] = "humidity%d_input",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) [hwmon_humidity_label] = "humidity%d_label",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) [hwmon_humidity_min] = "humidity%d_min",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) [hwmon_humidity_min_hyst] = "humidity%d_min_hyst",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) [hwmon_humidity_max] = "humidity%d_max",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) [hwmon_humidity_max_hyst] = "humidity%d_max_hyst",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) [hwmon_humidity_alarm] = "humidity%d_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) [hwmon_humidity_fault] = "humidity%d_fault",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) [hwmon_humidity_rated_min] = "humidity%d_rated_min",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) [hwmon_humidity_rated_max] = "humidity%d_rated_max",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) static const char * const hwmon_fan_attr_templates[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) [hwmon_fan_enable] = "fan%d_enable",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) [hwmon_fan_input] = "fan%d_input",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) [hwmon_fan_label] = "fan%d_label",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) [hwmon_fan_min] = "fan%d_min",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) [hwmon_fan_max] = "fan%d_max",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) [hwmon_fan_div] = "fan%d_div",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) [hwmon_fan_pulses] = "fan%d_pulses",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) [hwmon_fan_target] = "fan%d_target",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) [hwmon_fan_alarm] = "fan%d_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) [hwmon_fan_min_alarm] = "fan%d_min_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) [hwmon_fan_max_alarm] = "fan%d_max_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) [hwmon_fan_fault] = "fan%d_fault",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) static const char * const hwmon_pwm_attr_templates[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) [hwmon_pwm_input] = "pwm%d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) [hwmon_pwm_enable] = "pwm%d_enable",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) [hwmon_pwm_mode] = "pwm%d_mode",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) [hwmon_pwm_freq] = "pwm%d_freq",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) static const char * const hwmon_intrusion_attr_templates[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) [hwmon_intrusion_alarm] = "intrusion%d_alarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) [hwmon_intrusion_beep] = "intrusion%d_beep",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) static const char * const *__templates[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) [hwmon_chip] = hwmon_chip_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) [hwmon_temp] = hwmon_temp_attr_templates,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) [hwmon_in] = hwmon_in_attr_templates,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) [hwmon_curr] = hwmon_curr_attr_templates,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) [hwmon_power] = hwmon_power_attr_templates,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) [hwmon_energy] = hwmon_energy_attr_templates,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) [hwmon_humidity] = hwmon_humidity_attr_templates,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) [hwmon_fan] = hwmon_fan_attr_templates,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) [hwmon_pwm] = hwmon_pwm_attr_templates,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) [hwmon_intrusion] = hwmon_intrusion_attr_templates,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) static const int __templates_size[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) [hwmon_chip] = ARRAY_SIZE(hwmon_chip_attrs),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) [hwmon_temp] = ARRAY_SIZE(hwmon_temp_attr_templates),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) [hwmon_in] = ARRAY_SIZE(hwmon_in_attr_templates),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) [hwmon_curr] = ARRAY_SIZE(hwmon_curr_attr_templates),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) [hwmon_power] = ARRAY_SIZE(hwmon_power_attr_templates),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) [hwmon_energy] = ARRAY_SIZE(hwmon_energy_attr_templates),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) [hwmon_humidity] = ARRAY_SIZE(hwmon_humidity_attr_templates),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) [hwmon_fan] = ARRAY_SIZE(hwmon_fan_attr_templates),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) [hwmon_pwm] = ARRAY_SIZE(hwmon_pwm_attr_templates),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) [hwmon_intrusion] = ARRAY_SIZE(hwmon_intrusion_attr_templates),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) int hwmon_notify_event(struct device *dev, enum hwmon_sensor_types type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) u32 attr, int channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) char sattr[MAX_SYSFS_ATTR_NAME_LENGTH];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) const char * const *templates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) const char *template;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) int base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) if (type >= ARRAY_SIZE(__templates))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) if (attr >= __templates_size[type])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) templates = __templates[type];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) template = templates[attr];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) base = hwmon_attr_base(type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) scnprintf(sattr, MAX_SYSFS_ATTR_NAME_LENGTH, template, base + channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) sysfs_notify(&dev->kobj, NULL, sattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) kobject_uevent(&dev->kobj, KOBJ_CHANGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) if (type == hwmon_temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) hwmon_thermal_notify(dev, channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) EXPORT_SYMBOL_GPL(hwmon_notify_event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) static int hwmon_num_channel_attrs(const struct hwmon_channel_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) int i, n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) for (i = n = 0; info->config[i]; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) n += hweight32(info->config[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) return n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) static int hwmon_genattrs(const void *drvdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) struct attribute **attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) const struct hwmon_ops *ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) const struct hwmon_channel_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) const char * const *templates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) int template_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) int i, aindex = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) if (info->type >= ARRAY_SIZE(__templates))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) templates = __templates[info->type];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) template_size = __templates_size[info->type];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) for (i = 0; info->config[i]; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) u32 attr_mask = info->config[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) u32 attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) while (attr_mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) struct attribute *a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) attr = __ffs(attr_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) attr_mask &= ~BIT(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) if (attr >= template_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) a = hwmon_genattr(drvdata, info->type, attr, i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) templates[attr], ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) if (IS_ERR(a)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) if (PTR_ERR(a) != -ENOENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) return PTR_ERR(a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) attrs[aindex++] = a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) return aindex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) static struct attribute **
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) __hwmon_create_attrs(const void *drvdata, const struct hwmon_chip_info *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) int ret, i, aindex = 0, nattrs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) struct attribute **attrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) for (i = 0; chip->info[i]; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) nattrs += hwmon_num_channel_attrs(chip->info[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) if (nattrs == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) attrs = kcalloc(nattrs + 1, sizeof(*attrs), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if (!attrs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) for (i = 0; chip->info[i]; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) ret = hwmon_genattrs(drvdata, &attrs[aindex], chip->ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) chip->info[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) hwmon_free_attrs(attrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) aindex += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) return attrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) static struct device *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) const struct hwmon_chip_info *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) const struct attribute_group **groups)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) struct hwmon_device *hwdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) struct device *hdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) int i, err, id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) /* Complain about invalid characters in hwmon name attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) if (name && (!strlen(name) || strpbrk(name, "-* \t\n")))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) dev_warn(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) "hwmon: '%s' is not a valid name attribute, please fix\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) if (id < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) return ERR_PTR(id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) hwdev = kzalloc(sizeof(*hwdev), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) if (hwdev == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) goto ida_remove;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) hdev = &hwdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (chip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) struct attribute **attrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) int ngroups = 2; /* terminating NULL plus &hwdev->groups */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) if (groups)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) for (i = 0; groups[i]; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) ngroups++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) hwdev->groups = kcalloc(ngroups, sizeof(*groups), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) if (!hwdev->groups) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) goto free_hwmon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) attrs = __hwmon_create_attrs(drvdata, chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) if (IS_ERR(attrs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) err = PTR_ERR(attrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) goto free_hwmon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) hwdev->group.attrs = attrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) ngroups = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) hwdev->groups[ngroups++] = &hwdev->group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) if (groups) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) for (i = 0; groups[i]; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) hwdev->groups[ngroups++] = groups[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) hdev->groups = hwdev->groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) hdev->groups = groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) hwdev->name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) hdev->class = &hwmon_class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) hdev->parent = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) hdev->of_node = dev ? dev->of_node : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) hwdev->chip = chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) dev_set_drvdata(hdev, drvdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) dev_set_name(hdev, HWMON_ID_FORMAT, id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) err = device_register(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) put_device(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) goto ida_remove;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) INIT_LIST_HEAD(&hwdev->tzdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) if (dev && dev->of_node && chip && chip->ops->read &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) chip->info[0]->type == hwmon_chip &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) (chip->info[0]->config[0] & HWMON_C_REGISTER_TZ)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) err = hwmon_thermal_register_sensors(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) device_unregister(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) * Don't worry about hwdev; hwmon_dev_release(), called
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) * from device_unregister(), will free it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) goto ida_remove;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) return hdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) free_hwmon:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) hwmon_dev_release(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) ida_remove:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) ida_simple_remove(&hwmon_ida, id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) return ERR_PTR(err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) * hwmon_device_register_with_groups - register w/ hwmon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) * @dev: the parent device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) * @name: hwmon name attribute
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) * @drvdata: driver data to attach to created device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) * @groups: List of attribute groups to create
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) * hwmon_device_unregister() must be called when the device is no
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) * longer needed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) * Returns the pointer to the new device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) struct device *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) hwmon_device_register_with_groups(struct device *dev, const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) void *drvdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) const struct attribute_group **groups)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) if (!name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) return __hwmon_device_register(dev, name, drvdata, NULL, groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) EXPORT_SYMBOL_GPL(hwmon_device_register_with_groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) * hwmon_device_register_with_info - register w/ hwmon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) * @dev: the parent device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) * @name: hwmon name attribute
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) * @drvdata: driver data to attach to created device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) * @chip: pointer to hwmon chip information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) * @extra_groups: pointer to list of additional non-standard attribute groups
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) * hwmon_device_unregister() must be called when the device is no
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) * longer needed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) * Returns the pointer to the new device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) struct device *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) hwmon_device_register_with_info(struct device *dev, const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) void *drvdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) const struct hwmon_chip_info *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) const struct attribute_group **extra_groups)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) if (!name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) if (chip && (!chip->ops || !chip->ops->is_visible || !chip->info))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) if (chip && !dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) return __hwmon_device_register(dev, name, drvdata, chip, extra_groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) EXPORT_SYMBOL_GPL(hwmon_device_register_with_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) * hwmon_device_register - register w/ hwmon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) * @dev: the device to register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) * hwmon_device_unregister() must be called when the device is no
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) * longer needed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) * Returns the pointer to the new device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) struct device *hwmon_device_register(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) dev_warn(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) "hwmon_device_register() is deprecated. Please convert the driver to use hwmon_device_register_with_info().\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) return __hwmon_device_register(dev, NULL, NULL, NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) EXPORT_SYMBOL_GPL(hwmon_device_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) * hwmon_device_unregister - removes the previously registered class device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) * @dev: the class device to destroy
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) void hwmon_device_unregister(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) int id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) if (likely(sscanf(dev_name(dev), HWMON_ID_FORMAT, &id) == 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) device_unregister(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) ida_simple_remove(&hwmon_ida, id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) dev_dbg(dev->parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) "hwmon_device_unregister() failed: bad class ID!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) EXPORT_SYMBOL_GPL(hwmon_device_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) static void devm_hwmon_release(struct device *dev, void *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) struct device *hwdev = *(struct device **)res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) hwmon_device_unregister(hwdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) * devm_hwmon_device_register_with_groups - register w/ hwmon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) * @dev: the parent device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) * @name: hwmon name attribute
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) * @drvdata: driver data to attach to created device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) * @groups: List of attribute groups to create
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) * Returns the pointer to the new device. The new device is automatically
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) * unregistered with the parent device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) struct device *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) devm_hwmon_device_register_with_groups(struct device *dev, const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) void *drvdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) const struct attribute_group **groups)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) struct device **ptr, *hwdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) if (!dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) ptr = devres_alloc(devm_hwmon_release, sizeof(*ptr), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) if (!ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) hwdev = hwmon_device_register_with_groups(dev, name, drvdata, groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) if (IS_ERR(hwdev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) *ptr = hwdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) devres_add(dev, ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) return hwdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) devres_free(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) return hwdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) * devm_hwmon_device_register_with_info - register w/ hwmon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) * @dev: the parent device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) * @name: hwmon name attribute
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) * @drvdata: driver data to attach to created device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) * @chip: pointer to hwmon chip information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) * @groups: pointer to list of driver specific attribute groups
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) * Returns the pointer to the new device. The new device is automatically
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) * unregistered with the parent device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) struct device *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) devm_hwmon_device_register_with_info(struct device *dev, const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) void *drvdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) const struct hwmon_chip_info *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) const struct attribute_group **groups)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) struct device **ptr, *hwdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) if (!dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) ptr = devres_alloc(devm_hwmon_release, sizeof(*ptr), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) if (!ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) hwdev = hwmon_device_register_with_info(dev, name, drvdata, chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) if (IS_ERR(hwdev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) *ptr = hwdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) devres_add(dev, ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) return hwdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) devres_free(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) return hwdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) static int devm_hwmon_match(struct device *dev, void *res, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) struct device **hwdev = res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) return *hwdev == data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) * devm_hwmon_device_unregister - removes a previously registered hwmon device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) * @dev: the parent device of the device to unregister
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) void devm_hwmon_device_unregister(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) WARN_ON(devres_release(dev, devm_hwmon_release, devm_hwmon_match, dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) EXPORT_SYMBOL_GPL(devm_hwmon_device_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) static void __init hwmon_pci_quirks(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) #if defined CONFIG_X86 && defined CONFIG_PCI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) struct pci_dev *sb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) u16 base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) u8 enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) /* Open access to 0x295-0x296 on MSI MS-7031 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) if (sb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) if (sb->subsystem_vendor == 0x1462 && /* MSI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) sb->subsystem_device == 0x0031) { /* MS-7031 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) pci_read_config_byte(sb, 0x48, &enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) pci_read_config_word(sb, 0x64, &base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) if (base == 0 && !(enable & BIT(2))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) dev_info(&sb->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) "Opening wide generic port at 0x295\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) pci_write_config_word(sb, 0x64, 0x295);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) pci_write_config_byte(sb, 0x48,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) enable | BIT(2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) pci_dev_put(sb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) static int __init hwmon_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) hwmon_pci_quirks();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) err = class_register(&hwmon_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) pr_err("couldn't register hwmon sysfs class\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) static void __exit hwmon_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) class_unregister(&hwmon_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) subsys_initcall(hwmon_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) module_exit(hwmon_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) MODULE_DESCRIPTION("hardware monitoring sysfs/class support");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045)