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