aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2015-08-26 22:38:11 -0400
committerGuenter Roeck <linux@roeck-us.net>2016-09-09 00:34:15 -0400
commitd560168b5d0fb4a70c74b386564072a819d9bf71 (patch)
treea6547dcb07cfaa2ec52d6b52136d9ac9a66cecbc
parentc9ebbe6f23f43f4520d9e3c4fe1384963848088e (diff)
hwmon: (core) New hwmon registration API
Up to now, each hwmon driver has to implement its own sysfs attributes. This requires a lot of template code, and distracts from the driver's core function to read and write chip registers. To be able to reduce driver complexity, move sensor attribute handling and thermal zone registration into hwmon core. By using the new API, driver code and data size is typically reduced by 20-70%, depending on driver complexity and the number of sysfs attributes supported. With this patch, the new API only supports thermal sensors. Support for other sensor types will be added with subsequent patches. Acked-by: Punit Agrawal <punit.agrawal@arm.com> Reviewed-by: Jonathan Cameron <jic23@kernel.org> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r--drivers/hwmon/hwmon.c485
-rw-r--r--include/linux/hwmon.h148
2 files changed, 606 insertions, 27 deletions
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index 649a68d119b4..3e4cc442a089 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -12,6 +12,7 @@
12 12
13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14 14
15#include <linux/bitops.h>
15#include <linux/device.h> 16#include <linux/device.h>
16#include <linux/err.h> 17#include <linux/err.h>
17#include <linux/gfp.h> 18#include <linux/gfp.h>
@@ -21,6 +22,7 @@
21#include <linux/pci.h> 22#include <linux/pci.h>
22#include <linux/slab.h> 23#include <linux/slab.h>
23#include <linux/string.h> 24#include <linux/string.h>
25#include <linux/thermal.h>
24 26
25#define HWMON_ID_PREFIX "hwmon" 27#define HWMON_ID_PREFIX "hwmon"
26#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" 28#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
@@ -28,9 +30,35 @@
28struct hwmon_device { 30struct hwmon_device {
29 const char *name; 31 const char *name;
30 struct device dev; 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) 39#define to_hwmon_device(d) container_of(d, struct hwmon_device, dev)
33 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 62static ssize_t
35show_name(struct device *dev, struct device_attribute *attr, char *buf) 63show_name(struct device *dev, struct device_attribute *attr, char *buf)
36{ 64{
@@ -78,25 +106,286 @@ static struct class hwmon_class = {
78 106
79static DEFINE_IDA(hwmon_ida); 107static DEFINE_IDA(hwmon_ida);
80 108
81/** 109/* Thermal zone handling */
82 * hwmon_device_register_with_groups - register w/ hwmon 110
83 * @dev: the parent device 111#if IS_REACHABLE(CONFIG_THERMAL) && defined(CONFIG_THERMAL_OF)
84 * @name: hwmon name attribute 112static int hwmon_thermal_get_temp(void *data, int *temp)
85 * @drvdata: driver data to attach to created device 113{
86 * @groups: List of attribute groups to create 114 struct hwmon_thermal_data *tdata = data;
87 * 115 struct hwmon_device *hwdev = tdata->hwdev;
88 * hwmon_device_unregister() must be called when the device is no 116 int ret;
89 * longer needed. 117 long t;
90 * 118
91 * Returns the pointer to the new device. 119 ret = hwdev->chip->ops->read(&hwdev->dev, hwmon_temp, hwmon_temp_input,
92 */ 120 tdata->index, &t);
93struct device * 121 if (ret < 0)
94hwmon_device_register_with_groups(struct device *dev, const char *name, 122 return ret;
95 void *drvdata, 123
96 const struct attribute_group **groups) 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)
97{ 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 389
101 /* Do not accept invalid characters in hwmon name attribute */ 390 /* Do not accept invalid characters in hwmon name attribute */
102 if (name && (!strlen(name) || strpbrk(name, "-* \t\n"))) 391 if (name && (!strlen(name) || strpbrk(name, "-* \t\n")))
@@ -112,28 +401,128 @@ hwmon_device_register_with_groups(struct device *dev, const char *name,
112 goto ida_remove; 401 goto ida_remove;
113 } 402 }
114 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; 440 hdev->class = &hwmon_class;
117 hwdev->dev.parent = dev; 441 hdev->parent = dev;
118 hwdev->dev.groups = groups; 442 hdev->of_node = dev ? dev->of_node : NULL;
119 hwdev->dev.of_node = dev ? dev->of_node : NULL; 443 hwdev->chip = chip;
120 dev_set_drvdata(&hwdev->dev, drvdata); 444 dev_set_drvdata(hdev, drvdata);
121 dev_set_name(&hwdev->dev, HWMON_ID_FORMAT, id); 445 dev_set_name(hdev, HWMON_ID_FORMAT, id);
122 err = device_register(&hwdev->dev); 446 err = device_register(hdev);
123 if (err) 447 if (err)
124 goto free; 448 goto free_hwmon;
449
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;
454
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 }
125 468
126 return &hwdev->dev; 469 return hdev;
127 470
128free: 471free_hwmon:
129 kfree(hwdev); 472 kfree(hwdev);
130ida_remove: 473ida_remove:
131 ida_simple_remove(&hwmon_ida, id); 474 ida_simple_remove(&hwmon_ida, id);
132 return ERR_PTR(err); 475 return ERR_PTR(err);
133} 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); 497EXPORT_SYMBOL_GPL(hwmon_device_register_with_groups);
135 498
136/** 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 526 * hwmon_device_register - register w/ hwmon
138 * @dev: the device to register 527 * @dev: the device to register
139 * 528 *
@@ -211,6 +600,48 @@ error:
211} 600}
212EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_groups); 601EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_groups);
213 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) 645static int devm_hwmon_match(struct device *dev, void *res, void *data)
215{ 646{
216 struct device **hwdev = res; 647 struct device **hwdev = res;
diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h
index 09354f6c1d63..52e56d71d742 100644
--- a/include/linux/hwmon.h
+++ b/include/linux/hwmon.h
@@ -14,9 +14,147 @@
14#ifndef _HWMON_H_ 14#ifndef _HWMON_H_
15#define _HWMON_H_ 15#define _HWMON_H_
16 16
17#include <linux/bitops.h>
18
17struct device; 19struct device;
18struct attribute_group; 20struct attribute_group;
19 21
22enum hwmon_sensor_types {
23 hwmon_chip,
24 hwmon_temp,
25 hwmon_in,
26 hwmon_curr,
27 hwmon_power,
28 hwmon_energy,
29};
30
31enum hwmon_chip_attributes {
32 hwmon_chip_temp_reset_history,
33 hwmon_chip_register_tz,
34 hwmon_chip_update_interval,
35 hwmon_chip_alarms,
36};
37
38#define HWMON_C_TEMP_RESET_HISTORY BIT(hwmon_chip_temp_reset_history)
39#define HWMON_C_IN_RESET_HISTORY BIT(hwmon_chip_in_reset_history)
40#define HWMON_C_REGISTER_TZ BIT(hwmon_chip_register_tz)
41#define HWMON_C_UPDATE_INTERVAL BIT(hwmon_chip_update_interval)
42#define HWMON_C_ALARMS BIT(hwmon_chip_alarms)
43
44enum hwmon_temp_attributes {
45 hwmon_temp_input = 0,
46 hwmon_temp_type,
47 hwmon_temp_lcrit,
48 hwmon_temp_lcrit_hyst,
49 hwmon_temp_min,
50 hwmon_temp_min_hyst,
51 hwmon_temp_max,
52 hwmon_temp_max_hyst,
53 hwmon_temp_crit,
54 hwmon_temp_crit_hyst,
55 hwmon_temp_emergency,
56 hwmon_temp_emergency_hyst,
57 hwmon_temp_alarm,
58 hwmon_temp_lcrit_alarm,
59 hwmon_temp_min_alarm,
60 hwmon_temp_max_alarm,
61 hwmon_temp_crit_alarm,
62 hwmon_temp_emergency_alarm,
63 hwmon_temp_fault,
64 hwmon_temp_offset,
65 hwmon_temp_label,
66 hwmon_temp_lowest,
67 hwmon_temp_highest,
68 hwmon_temp_reset_history,
69};
70
71#define HWMON_T_INPUT BIT(hwmon_temp_input)
72#define HWMON_T_TYPE BIT(hwmon_temp_type)
73#define HWMON_T_LCRIT BIT(hwmon_temp_lcrit)
74#define HWMON_T_LCRIT_HYST BIT(hwmon_temp_lcrit_hyst)
75#define HWMON_T_MIN BIT(hwmon_temp_min)
76#define HWMON_T_MIN_HYST BIT(hwmon_temp_min_hyst)
77#define HWMON_T_MAX BIT(hwmon_temp_max)
78#define HWMON_T_MAX_HYST BIT(hwmon_temp_max_hyst)
79#define HWMON_T_CRIT BIT(hwmon_temp_crit)
80#define HWMON_T_CRIT_HYST BIT(hwmon_temp_crit_hyst)
81#define HWMON_T_EMERGENCY BIT(hwmon_temp_emergency)
82#define HWMON_T_EMERGENCY_HYST BIT(hwmon_temp_emergency_hyst)
83#define HWMON_T_MIN_ALARM BIT(hwmon_temp_min_alarm)
84#define HWMON_T_MAX_ALARM BIT(hwmon_temp_max_alarm)
85#define HWMON_T_CRIT_ALARM BIT(hwmon_temp_crit_alarm)
86#define HWMON_T_EMERGENCY_ALARM BIT(hwmon_temp_emergency_alarm)
87#define HWMON_T_FAULT BIT(hwmon_temp_fault)
88#define HWMON_T_OFFSET BIT(hwmon_temp_offset)
89#define HWMON_T_LABEL BIT(hwmon_temp_label)
90#define HWMON_T_LOWEST BIT(hwmon_temp_lowest)
91#define HWMON_T_HIGHEST BIT(hwmon_temp_highest)
92#define HWMON_T_RESET_HISTORY BIT(hwmon_temp_reset_history)
93
94/**
95 * struct hwmon_ops - hwmon device operations
96 * @is_visible: Callback to return attribute visibility. Mandatory.
97 * Parameters are:
98 * @const void *drvdata:
99 * Pointer to driver-private data structure passed
100 * as argument to hwmon_device_register_with_info().
101 * @type: Sensor type
102 * @attr: Sensor attribute
103 * @channel:
104 * Channel number
105 * The function returns the file permissions.
106 * If the return value is 0, no attribute will be created.
107 * @read: Read callback. Optional. If not provided, attributes
108 * will not be readable.
109 * Parameters are:
110 * @dev: Pointer to hardware monitoring device
111 * @type: Sensor type
112 * @attr: Sensor attribute
113 * @channel:
114 * Channel number
115 * @val: Pointer to returned value
116 * The function returns 0 on success or a negative error number.
117 * @write: Write callback. Optional. If not provided, attributes
118 * will not be writable.
119 * Parameters are:
120 * @dev: Pointer to hardware monitoring device
121 * @type: Sensor type
122 * @attr: Sensor attribute
123 * @channel:
124 * Channel number
125 * @val: Value to write
126 * The function returns 0 on success or a negative error number.
127 */
128struct hwmon_ops {
129 umode_t (*is_visible)(const void *drvdata, enum hwmon_sensor_types type,
130 u32 attr, int channel);
131 int (*read)(struct device *dev, enum hwmon_sensor_types type,
132 u32 attr, int channel, long *val);
133 int (*write)(struct device *dev, enum hwmon_sensor_types type,
134 u32 attr, int channel, long val);
135};
136
137/**
138 * Channel information
139 * @type: Channel type.
140 * @config: Pointer to NULL-terminated list of channel parameters.
141 * Use for per-channel attributes.
142 */
143struct hwmon_channel_info {
144 enum hwmon_sensor_types type;
145 const u32 *config;
146};
147
148/**
149 * Chip configuration
150 * @ops: Pointer to hwmon operations.
151 * @info: Null-terminated list of channel information.
152 */
153struct hwmon_chip_info {
154 const struct hwmon_ops *ops;
155 const struct hwmon_channel_info **info;
156};
157
20struct device *hwmon_device_register(struct device *dev); 158struct device *hwmon_device_register(struct device *dev);
21struct device * 159struct device *
22hwmon_device_register_with_groups(struct device *dev, const char *name, 160hwmon_device_register_with_groups(struct device *dev, const char *name,
@@ -26,6 +164,16 @@ struct device *
26devm_hwmon_device_register_with_groups(struct device *dev, const char *name, 164devm_hwmon_device_register_with_groups(struct device *dev, const char *name,
27 void *drvdata, 165 void *drvdata,
28 const struct attribute_group **groups); 166 const struct attribute_group **groups);
167struct device *
168hwmon_device_register_with_info(struct device *dev,
169 const char *name, void *drvdata,
170 const struct hwmon_chip_info *info,
171 const struct attribute_group **groups);
172struct device *
173devm_hwmon_device_register_with_info(struct device *dev,
174 const char *name, void *drvdata,
175 const struct hwmon_chip_info *info,
176 const struct attribute_group **groups);
29 177
30void hwmon_device_unregister(struct device *dev); 178void hwmon_device_unregister(struct device *dev);
31void devm_hwmon_device_unregister(struct device *dev); 179void devm_hwmon_device_unregister(struct device *dev);