hwmon.c (c9ebbe6f23f43f4520d9e3c4fe1384963848088e) | hwmon.c (d560168b5d0fb4a70c74b386564072a819d9bf71) |
---|---|
1/* 2 * hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring 3 * 4 * This file defines the sysfs class "hwmon", for use by sensors drivers. 5 * 6 * Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; version 2 of the License. 11 */ 12 13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14 | 1/* 2 * hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring 3 * 4 * This file defines the sysfs class "hwmon", for use by sensors drivers. 5 * 6 * Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; version 2 of the License. 11 */ 12 13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14 |
15#include <linux/bitops.h> |
|
15#include <linux/device.h> 16#include <linux/err.h> 17#include <linux/gfp.h> 18#include <linux/hwmon.h> 19#include <linux/idr.h> 20#include <linux/module.h> 21#include <linux/pci.h> 22#include <linux/slab.h> 23#include <linux/string.h> | 16#include <linux/device.h> 17#include <linux/err.h> 18#include <linux/gfp.h> 19#include <linux/hwmon.h> 20#include <linux/idr.h> 21#include <linux/module.h> 22#include <linux/pci.h> 23#include <linux/slab.h> 24#include <linux/string.h> |
25#include <linux/thermal.h> |
|
24 25#define HWMON_ID_PREFIX "hwmon" 26#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" 27 28struct hwmon_device { 29 const char *name; 30 struct device dev; | 26 27#define HWMON_ID_PREFIX "hwmon" 28#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" 29 30struct hwmon_device { 31 const char *name; 32 struct device dev; |
33 const struct hwmon_chip_info *chip; 34 35 struct attribute_group group; 36 const struct attribute_group **groups; |
|
31}; | 37}; |
38 |
|
32#define to_hwmon_device(d) container_of(d, struct hwmon_device, dev) 33 | 39#define to_hwmon_device(d) container_of(d, struct hwmon_device, dev) 40 |
41struct hwmon_device_attribute { 42 struct device_attribute dev_attr; 43 const struct hwmon_ops *ops; 44 enum hwmon_sensor_types type; 45 u32 attr; 46 int index; 47}; 48 49#define to_hwmon_attr(d) \ 50 container_of(d, struct hwmon_device_attribute, dev_attr) 51 52/* 53 * Thermal zone information 54 * In addition to the reference to the hwmon device, 55 * also provides the sensor index. 56 */ 57struct hwmon_thermal_data { 58 struct hwmon_device *hwdev; /* Reference to hwmon device */ 59 int index; /* sensor index */ 60}; 61 |
|
34static ssize_t 35show_name(struct device *dev, struct device_attribute *attr, char *buf) 36{ 37 return sprintf(buf, "%s\n", to_hwmon_device(dev)->name); 38} 39static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); 40 41static struct attribute *hwmon_dev_attrs[] = { --- 31 unchanged lines hidden (view full) --- 73 .name = "hwmon", 74 .owner = THIS_MODULE, 75 .dev_groups = hwmon_dev_attr_groups, 76 .dev_release = hwmon_dev_release, 77}; 78 79static DEFINE_IDA(hwmon_ida); 80 | 62static ssize_t 63show_name(struct device *dev, struct device_attribute *attr, char *buf) 64{ 65 return sprintf(buf, "%s\n", to_hwmon_device(dev)->name); 66} 67static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); 68 69static struct attribute *hwmon_dev_attrs[] = { --- 31 unchanged lines hidden (view full) --- 101 .name = "hwmon", 102 .owner = THIS_MODULE, 103 .dev_groups = hwmon_dev_attr_groups, 104 .dev_release = hwmon_dev_release, 105}; 106 107static DEFINE_IDA(hwmon_ida); 108 |
81/** 82 * hwmon_device_register_with_groups - register w/ hwmon 83 * @dev: the parent device 84 * @name: hwmon name attribute 85 * @drvdata: driver data to attach to created device 86 * @groups: List of attribute groups to create 87 * 88 * hwmon_device_unregister() must be called when the device is no 89 * longer needed. 90 * 91 * Returns the pointer to the new device. 92 */ 93struct device * 94hwmon_device_register_with_groups(struct device *dev, const char *name, 95 void *drvdata, 96 const struct attribute_group **groups) | 109/* Thermal zone handling */ 110 111#if IS_REACHABLE(CONFIG_THERMAL) && defined(CONFIG_THERMAL_OF) 112static int hwmon_thermal_get_temp(void *data, int *temp) |
97{ | 113{ |
114 struct hwmon_thermal_data *tdata = data; 115 struct hwmon_device *hwdev = tdata->hwdev; 116 int ret; 117 long t; 118 119 ret = hwdev->chip->ops->read(&hwdev->dev, hwmon_temp, hwmon_temp_input, 120 tdata->index, &t); 121 if (ret < 0) 122 return ret; 123 124 *temp = t; 125 126 return 0; 127} 128 129static struct thermal_zone_of_device_ops hwmon_thermal_ops = { 130 .get_temp = hwmon_thermal_get_temp, 131}; 132 133static int hwmon_thermal_add_sensor(struct device *dev, 134 struct hwmon_device *hwdev, int index) 135{ 136 struct hwmon_thermal_data *tdata; 137 138 tdata = devm_kzalloc(dev, sizeof(*tdata), GFP_KERNEL); 139 if (!tdata) 140 return -ENOMEM; 141 142 tdata->hwdev = hwdev; 143 tdata->index = index; 144 145 devm_thermal_zone_of_sensor_register(&hwdev->dev, index, tdata, 146 &hwmon_thermal_ops); 147 148 return 0; 149} 150#else 151static int hwmon_thermal_add_sensor(struct device *dev, 152 struct hwmon_device *hwdev, int index) 153{ 154 return 0; 155} 156#endif /* IS_REACHABLE(CONFIG_THERMAL) && defined(CONFIG_THERMAL_OF) */ 157 158/* sysfs attribute management */ 159 160static ssize_t hwmon_attr_show(struct device *dev, 161 struct device_attribute *devattr, char *buf) 162{ 163 struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); 164 long val; 165 int ret; 166 167 ret = hattr->ops->read(dev, hattr->type, hattr->attr, hattr->index, 168 &val); 169 if (ret < 0) 170 return ret; 171 172 return sprintf(buf, "%ld\n", val); 173} 174 175static ssize_t hwmon_attr_store(struct device *dev, 176 struct device_attribute *devattr, 177 const char *buf, size_t count) 178{ 179 struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); 180 long val; 181 int ret; 182 183 ret = kstrtol(buf, 10, &val); 184 if (ret < 0) 185 return ret; 186 187 ret = hattr->ops->write(dev, hattr->type, hattr->attr, hattr->index, 188 val); 189 if (ret < 0) 190 return ret; 191 192 return count; 193} 194 195static int hwmon_attr_base(enum hwmon_sensor_types type) 196{ 197 if (type == hwmon_in) 198 return 0; 199 return 1; 200} 201 202static struct attribute *hwmon_genattr(struct device *dev, 203 const void *drvdata, 204 enum hwmon_sensor_types type, 205 u32 attr, 206 int index, 207 const char *template, 208 const struct hwmon_ops *ops) 209{ 210 struct hwmon_device_attribute *hattr; 211 struct device_attribute *dattr; 212 struct attribute *a; 213 umode_t mode; 214 char *name; 215 216 /* The attribute is invisible if there is no template string */ 217 if (!template) 218 return ERR_PTR(-ENOENT); 219 220 mode = ops->is_visible(drvdata, type, attr, index); 221 if (!mode) 222 return ERR_PTR(-ENOENT); 223 224 if ((mode & S_IRUGO) && !ops->read) 225 return ERR_PTR(-EINVAL); 226 if ((mode & S_IWUGO) && !ops->write) 227 return ERR_PTR(-EINVAL); 228 229 if (type == hwmon_chip) { 230 name = (char *)template; 231 } else { 232 name = devm_kzalloc(dev, strlen(template) + 16, GFP_KERNEL); 233 if (!name) 234 return ERR_PTR(-ENOMEM); 235 scnprintf(name, strlen(template) + 16, template, 236 index + hwmon_attr_base(type)); 237 } 238 239 hattr = devm_kzalloc(dev, sizeof(*hattr), GFP_KERNEL); 240 if (!hattr) 241 return ERR_PTR(-ENOMEM); 242 243 hattr->type = type; 244 hattr->attr = attr; 245 hattr->index = index; 246 hattr->ops = ops; 247 248 dattr = &hattr->dev_attr; 249 dattr->show = hwmon_attr_show; 250 dattr->store = hwmon_attr_store; 251 252 a = &dattr->attr; 253 sysfs_attr_init(a); 254 a->name = name; 255 a->mode = mode; 256 257 return a; 258} 259 260static const char * const hwmon_chip_attr_templates[] = { 261 [hwmon_chip_temp_reset_history] = "temp_reset_history", 262 [hwmon_chip_update_interval] = "update_interval", 263 [hwmon_chip_alarms] = "alarms", 264}; 265 266static const char * const hwmon_temp_attr_templates[] = { 267 [hwmon_temp_input] = "temp%d_input", 268 [hwmon_temp_type] = "temp%d_type", 269 [hwmon_temp_lcrit] = "temp%d_lcrit", 270 [hwmon_temp_lcrit_hyst] = "temp%d_lcrit_hyst", 271 [hwmon_temp_min] = "temp%d_min", 272 [hwmon_temp_min_hyst] = "temp%d_min_hyst", 273 [hwmon_temp_max] = "temp%d_max", 274 [hwmon_temp_max_hyst] = "temp%d_max_hyst", 275 [hwmon_temp_crit] = "temp%d_crit", 276 [hwmon_temp_crit_hyst] = "temp%d_crit_hyst", 277 [hwmon_temp_emergency] = "temp%d_emergency", 278 [hwmon_temp_emergency_hyst] = "temp%d_emergency_hyst", 279 [hwmon_temp_alarm] = "temp%d_alarm", 280 [hwmon_temp_lcrit_alarm] = "temp%d_lcrit_alarm", 281 [hwmon_temp_min_alarm] = "temp%d_min_alarm", 282 [hwmon_temp_max_alarm] = "temp%d_max_alarm", 283 [hwmon_temp_crit_alarm] = "temp%d_crit_alarm", 284 [hwmon_temp_emergency_alarm] = "temp%d_emergency_alarm", 285 [hwmon_temp_fault] = "temp%d_fault", 286 [hwmon_temp_offset] = "temp%d_offset", 287 [hwmon_temp_label] = "temp%d_label", 288 [hwmon_temp_lowest] = "temp%d_lowest", 289 [hwmon_temp_highest] = "temp%d_highest", 290 [hwmon_temp_reset_history] = "temp%d_reset_history", 291}; 292 293static const char * const *__templates[] = { 294 [hwmon_chip] = hwmon_chip_attr_templates, 295 [hwmon_temp] = hwmon_temp_attr_templates, 296}; 297 298static const int __templates_size[] = { 299 [hwmon_chip] = ARRAY_SIZE(hwmon_chip_attr_templates), 300 [hwmon_temp] = ARRAY_SIZE(hwmon_temp_attr_templates), 301}; 302 303static int hwmon_num_channel_attrs(const struct hwmon_channel_info *info) 304{ 305 int i, n; 306 307 for (i = n = 0; info->config[i]; i++) 308 n += hweight32(info->config[i]); 309 310 return n; 311} 312 313static int hwmon_genattrs(struct device *dev, 314 const void *drvdata, 315 struct attribute **attrs, 316 const struct hwmon_ops *ops, 317 const struct hwmon_channel_info *info) 318{ 319 const char * const *templates; 320 int template_size; 321 int i, aindex = 0; 322 323 if (info->type >= ARRAY_SIZE(__templates)) 324 return -EINVAL; 325 326 templates = __templates[info->type]; 327 template_size = __templates_size[info->type]; 328 329 for (i = 0; info->config[i]; i++) { 330 u32 attr_mask = info->config[i]; 331 u32 attr; 332 333 while (attr_mask) { 334 struct attribute *a; 335 336 attr = __ffs(attr_mask); 337 attr_mask &= ~BIT(attr); 338 if (attr >= template_size) 339 return -EINVAL; 340 a = hwmon_genattr(dev, drvdata, info->type, attr, i, 341 templates[attr], ops); 342 if (IS_ERR(a)) { 343 if (PTR_ERR(a) != -ENOENT) 344 return PTR_ERR(a); 345 continue; 346 } 347 attrs[aindex++] = a; 348 } 349 } 350 return aindex; 351} 352 353static struct attribute ** 354__hwmon_create_attrs(struct device *dev, const void *drvdata, 355 const struct hwmon_chip_info *chip) 356{ 357 int ret, i, aindex = 0, nattrs = 0; 358 struct attribute **attrs; 359 360 for (i = 0; chip->info[i]; i++) 361 nattrs += hwmon_num_channel_attrs(chip->info[i]); 362 363 if (nattrs == 0) 364 return ERR_PTR(-EINVAL); 365 366 attrs = devm_kcalloc(dev, nattrs + 1, sizeof(*attrs), GFP_KERNEL); 367 if (!attrs) 368 return ERR_PTR(-ENOMEM); 369 370 for (i = 0; chip->info[i]; i++) { 371 ret = hwmon_genattrs(dev, drvdata, &attrs[aindex], chip->ops, 372 chip->info[i]); 373 if (ret < 0) 374 return ERR_PTR(ret); 375 aindex += ret; 376 } 377 378 return attrs; 379} 380 381static struct device * 382__hwmon_device_register(struct device *dev, const char *name, void *drvdata, 383 const struct hwmon_chip_info *chip, 384 const struct attribute_group **groups) 385{ |
|
98 struct hwmon_device *hwdev; | 386 struct hwmon_device *hwdev; |
99 int err, id; | 387 struct device *hdev; 388 int i, j, err, id; |
100 101 /* Do not accept invalid characters in hwmon name attribute */ 102 if (name && (!strlen(name) || strpbrk(name, "-* \t\n"))) 103 return ERR_PTR(-EINVAL); 104 105 id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL); 106 if (id < 0) 107 return ERR_PTR(id); 108 109 hwdev = kzalloc(sizeof(*hwdev), GFP_KERNEL); 110 if (hwdev == NULL) { 111 err = -ENOMEM; 112 goto ida_remove; 113 } 114 | 389 390 /* Do not accept invalid characters in hwmon name attribute */ 391 if (name && (!strlen(name) || strpbrk(name, "-* \t\n"))) 392 return ERR_PTR(-EINVAL); 393 394 id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL); 395 if (id < 0) 396 return ERR_PTR(id); 397 398 hwdev = kzalloc(sizeof(*hwdev), GFP_KERNEL); 399 if (hwdev == NULL) { 400 err = -ENOMEM; 401 goto ida_remove; 402 } 403 |
404 hdev = &hwdev->dev; 405 406 if (chip && chip->ops->is_visible) { 407 struct attribute **attrs; 408 int ngroups = 2; 409 410 if (groups) 411 for (i = 0; groups[i]; i++) 412 ngroups++; 413 414 hwdev->groups = devm_kcalloc(dev, ngroups, sizeof(*groups), 415 GFP_KERNEL); 416 if (!hwdev->groups) 417 return ERR_PTR(-ENOMEM); 418 419 attrs = __hwmon_create_attrs(dev, drvdata, chip); 420 if (IS_ERR(attrs)) { 421 err = PTR_ERR(attrs); 422 goto free_hwmon; 423 } 424 425 hwdev->group.attrs = attrs; 426 ngroups = 0; 427 hwdev->groups[ngroups++] = &hwdev->group; 428 429 if (groups) { 430 for (i = 0; groups[i]; i++) 431 hwdev->groups[ngroups++] = groups[i]; 432 } 433 434 hdev->groups = hwdev->groups; 435 } else { 436 hdev->groups = groups; 437 } 438 |
|
115 hwdev->name = name; | 439 hwdev->name = name; |
116 hwdev->dev.class = &hwmon_class; 117 hwdev->dev.parent = dev; 118 hwdev->dev.groups = groups; 119 hwdev->dev.of_node = dev ? dev->of_node : NULL; 120 dev_set_drvdata(&hwdev->dev, drvdata); 121 dev_set_name(&hwdev->dev, HWMON_ID_FORMAT, id); 122 err = device_register(&hwdev->dev); | 440 hdev->class = &hwmon_class; 441 hdev->parent = dev; 442 hdev->of_node = dev ? dev->of_node : NULL; 443 hwdev->chip = chip; 444 dev_set_drvdata(hdev, drvdata); 445 dev_set_name(hdev, HWMON_ID_FORMAT, id); 446 err = device_register(hdev); |
123 if (err) | 447 if (err) |
124 goto free; | 448 goto free_hwmon; |
125 | 449 |
126 return &hwdev->dev; | 450 if (chip && chip->ops->is_visible && chip->ops->read && 451 chip->info[0]->type == hwmon_chip && 452 (chip->info[0]->config[0] & HWMON_C_REGISTER_TZ)) { 453 const struct hwmon_channel_info **info = chip->info; |
127 | 454 |
128free: | 455 for (i = 1; info[i]; i++) { 456 if (info[i]->type != hwmon_temp) 457 continue; 458 459 for (j = 0; info[i]->config[j]; j++) { 460 if (!chip->ops->is_visible(drvdata, hwmon_temp, 461 hwmon_temp_input, j)) 462 continue; 463 if (info[i]->config[j] & HWMON_T_INPUT) 464 hwmon_thermal_add_sensor(dev, hwdev, j); 465 } 466 } 467 } 468 469 return hdev; 470 471free_hwmon: |
129 kfree(hwdev); 130ida_remove: 131 ida_simple_remove(&hwmon_ida, id); 132 return ERR_PTR(err); 133} | 472 kfree(hwdev); 473ida_remove: 474 ida_simple_remove(&hwmon_ida, id); 475 return ERR_PTR(err); 476} |
477 478/** 479 * hwmon_device_register_with_groups - register w/ hwmon 480 * @dev: the parent device 481 * @name: hwmon name attribute 482 * @drvdata: driver data to attach to created device 483 * @groups: List of attribute groups to create 484 * 485 * hwmon_device_unregister() must be called when the device is no 486 * longer needed. 487 * 488 * Returns the pointer to the new device. 489 */ 490struct device * 491hwmon_device_register_with_groups(struct device *dev, const char *name, 492 void *drvdata, 493 const struct attribute_group **groups) 494{ 495 return __hwmon_device_register(dev, name, drvdata, NULL, groups); 496} |
|
134EXPORT_SYMBOL_GPL(hwmon_device_register_with_groups); 135 136/** | 497EXPORT_SYMBOL_GPL(hwmon_device_register_with_groups); 498 499/** |
500 * hwmon_device_register_with_info - register w/ hwmon 501 * @dev: the parent device 502 * @name: hwmon name attribute 503 * @drvdata: driver data to attach to created device 504 * @info: Pointer to hwmon chip information 505 * @groups - pointer to list of driver specific attribute groups 506 * 507 * hwmon_device_unregister() must be called when the device is no 508 * longer needed. 509 * 510 * Returns the pointer to the new device. 511 */ 512struct device * 513hwmon_device_register_with_info(struct device *dev, const char *name, 514 void *drvdata, 515 const struct hwmon_chip_info *chip, 516 const struct attribute_group **groups) 517{ 518 if (chip && (!chip->ops || !chip->info)) 519 return ERR_PTR(-EINVAL); 520 521 return __hwmon_device_register(dev, name, drvdata, chip, groups); 522} 523EXPORT_SYMBOL_GPL(hwmon_device_register_with_info); 524 525/** |
|
137 * hwmon_device_register - register w/ hwmon 138 * @dev: the device to register 139 * 140 * hwmon_device_unregister() must be called when the device is no 141 * longer needed. 142 * 143 * Returns the pointer to the new device. 144 */ --- 61 unchanged lines hidden (view full) --- 206 return hwdev; 207 208error: 209 devres_free(ptr); 210 return hwdev; 211} 212EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_groups); 213 | 526 * hwmon_device_register - register w/ hwmon 527 * @dev: the device to register 528 * 529 * hwmon_device_unregister() must be called when the device is no 530 * longer needed. 531 * 532 * Returns the pointer to the new device. 533 */ --- 61 unchanged lines hidden (view full) --- 595 return hwdev; 596 597error: 598 devres_free(ptr); 599 return hwdev; 600} 601EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_groups); 602 |
603/** 604 * devm_hwmon_device_register_with_info - register w/ hwmon 605 * @dev: the parent device 606 * @name: hwmon name attribute 607 * @drvdata: driver data to attach to created device 608 * @info: Pointer to hwmon chip information 609 * @groups - pointer to list of driver specific attribute groups 610 * 611 * Returns the pointer to the new device. The new device is automatically 612 * unregistered with the parent device. 613 */ 614struct device * 615devm_hwmon_device_register_with_info(struct device *dev, const char *name, 616 void *drvdata, 617 const struct hwmon_chip_info *chip, 618 const struct attribute_group **groups) 619{ 620 struct device **ptr, *hwdev; 621 622 if (!dev) 623 return ERR_PTR(-EINVAL); 624 625 ptr = devres_alloc(devm_hwmon_release, sizeof(*ptr), GFP_KERNEL); 626 if (!ptr) 627 return ERR_PTR(-ENOMEM); 628 629 hwdev = hwmon_device_register_with_info(dev, name, drvdata, chip, 630 groups); 631 if (IS_ERR(hwdev)) 632 goto error; 633 634 *ptr = hwdev; 635 devres_add(dev, ptr); 636 637 return hwdev; 638 639error: 640 devres_free(ptr); 641 return hwdev; 642} 643EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_info); 644 |
|
214static int devm_hwmon_match(struct device *dev, void *res, void *data) 215{ 216 struct device **hwdev = res; 217 218 return *hwdev == data; 219} 220 221/** --- 64 unchanged lines hidden --- | 645static int devm_hwmon_match(struct device *dev, void *res, void *data) 646{ 647 struct device **hwdev = res; 648 649 return *hwdev == data; 650} 651 652/** --- 64 unchanged lines hidden --- |