Blame view

drivers/hwmon/hwmon.c 27.2 KB
b886d83c5   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
2
  /*
5ed04880a   Guenter Roeck   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   Guenter Roeck   hwmon: (hwmon) Fi...
8
   */
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
9

c95df1ae6   Joe Perches   hwmon: (core) Use...
10
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
d560168b5   Guenter Roeck   hwmon: (core) New...
11
  #include <linux/bitops.h>
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
12
13
  #include <linux/device.h>
  #include <linux/err.h>
8c65b4a60   Tim Schmielau   [PATCH] fix remai...
14
  #include <linux/gfp.h>
c9ebbe6f2   Guenter Roeck   hwmon: (core) Ord...
15
16
  #include <linux/hwmon.h>
  #include <linux/idr.h>
1597b374a   Guenter Roeck   hwmon: Add notifi...
17
  #include <linux/list.h>
c9ebbe6f2   Guenter Roeck   hwmon: (core) Ord...
18
  #include <linux/module.h>
2958b1ec6   Jean Delvare   hwmon: PCI quirk ...
19
  #include <linux/pci.h>
c9ebbe6f2   Guenter Roeck   hwmon: (core) Ord...
20
  #include <linux/slab.h>
648cd48c9   Guenter Roeck   hwmon: Do not acc...
21
  #include <linux/string.h>
d560168b5   Guenter Roeck   hwmon: (core) New...
22
  #include <linux/thermal.h>
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
23

61b8ab2c5   Nicolin Chen   hwmon: (core) Add...
24
25
  #define CREATE_TRACE_POINTS
  #include <trace/events/hwmon.h>
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
26
27
  #define HWMON_ID_PREFIX "hwmon"
  #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
bab2243ce   Guenter Roeck   hwmon: Introduce ...
28
29
30
  struct hwmon_device {
  	const char *name;
  	struct device dev;
d560168b5   Guenter Roeck   hwmon: (core) New...
31
  	const struct hwmon_chip_info *chip;
1597b374a   Guenter Roeck   hwmon: Add notifi...
32
  	struct list_head tzdata;
d560168b5   Guenter Roeck   hwmon: (core) New...
33
34
  	struct attribute_group group;
  	const struct attribute_group **groups;
bab2243ce   Guenter Roeck   hwmon: Introduce ...
35
  };
d560168b5   Guenter Roeck   hwmon: (core) New...
36

bab2243ce   Guenter Roeck   hwmon: Introduce ...
37
  #define to_hwmon_device(d) container_of(d, struct hwmon_device, dev)
3a412d5e4   Guenter Roeck   hwmon: (core) Sim...
38
  #define MAX_SYSFS_ATTR_NAME_LENGTH	32
d560168b5   Guenter Roeck   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   Guenter Roeck   hwmon: (core) Sim...
45
  	char name[MAX_SYSFS_ATTR_NAME_LENGTH];
d560168b5   Guenter Roeck   hwmon: (core) New...
46
47
48
49
  };
  
  #define to_hwmon_attr(d) \
  	container_of(d, struct hwmon_device_attribute, dev_attr)
3bf8bdcf3   Guenter Roeck   hwmon: (core) Do ...
50
  #define to_dev_attr(a) container_of(a, struct device_attribute, attr)
d560168b5   Guenter Roeck   hwmon: (core) New...
51
52
53
  
  /*
   * Thermal zone information
d560168b5   Guenter Roeck   hwmon: (core) New...
54
55
   */
  struct hwmon_thermal_data {
1597b374a   Guenter Roeck   hwmon: Add notifi...
56
  	struct list_head node;		/* hwmon tzdata list entry */
3bf8bdcf3   Guenter Roeck   hwmon: (core) Do ...
57
  	struct device *dev;		/* Reference to hwmon device */
d560168b5   Guenter Roeck   hwmon: (core) New...
58
  	int index;			/* sensor index */
1597b374a   Guenter Roeck   hwmon: Add notifi...
59
  	struct thermal_zone_device *tzd;/* thermal zone device */
d560168b5   Guenter Roeck   hwmon: (core) New...
60
  };
bab2243ce   Guenter Roeck   hwmon: Introduce ...
61
  static ssize_t
2ab0c6c55   Julia Lawall   hwmon: (core) use...
62
  name_show(struct device *dev, struct device_attribute *attr, char *buf)
bab2243ce   Guenter Roeck   hwmon: Introduce ...
63
64
65
66
  {
  	return sprintf(buf, "%s
  ", to_hwmon_device(dev)->name);
  }
2ab0c6c55   Julia Lawall   hwmon: (core) use...
67
  static DEVICE_ATTR_RO(name);
bab2243ce   Guenter Roeck   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   Arvind Yadav   hwmon: constify a...
84
  static const struct attribute_group hwmon_dev_attr_group = {
bab2243ce   Guenter Roeck   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   Guenter Roeck   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   Guenter Roeck   hwmon: Introduce ...
105
106
  static void hwmon_dev_release(struct device *dev)
  {
3bf8bdcf3   Guenter Roeck   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   Guenter Roeck   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   Mark M. Hoffman   [PATCH] I2C hwmon...
121

4ca5f468c   Jonathan Cameron   hwmon: convert id...
122
  static DEFINE_IDA(hwmon_ida);
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
123

d560168b5   Guenter Roeck   hwmon: (core) New...
124
  /* Thermal zone handling */
86430c1a6   Guenter Roeck   hwmon: (core) Avo...
125
126
127
128
  /*
   * The complex conditional is necessary to avoid a cyclic dependency
   * between hwmon and thermal_sys modules.
   */
f37353320   Daniel Lezcano   hwmon/drivers/cor...
129
  #ifdef CONFIG_THERMAL_OF
d560168b5   Guenter Roeck   hwmon: (core) New...
130
131
132
  static int hwmon_thermal_get_temp(void *data, int *temp)
  {
  	struct hwmon_thermal_data *tdata = data;
3bf8bdcf3   Guenter Roeck   hwmon: (core) Do ...
133
  	struct hwmon_device *hwdev = to_hwmon_device(tdata->dev);
d560168b5   Guenter Roeck   hwmon: (core) New...
134
135
  	int ret;
  	long t;
3bf8bdcf3   Guenter Roeck   hwmon: (core) Do ...
136
  	ret = hwdev->chip->ops->read(tdata->dev, hwmon_temp, hwmon_temp_input,
d560168b5   Guenter Roeck   hwmon: (core) New...
137
138
139
140
141
142
143
144
  				     tdata->index, &t);
  	if (ret < 0)
  		return ret;
  
  	*temp = t;
  
  	return 0;
  }
c9920650c   Julia Lawall   hwmon: (core) con...
145
  static const struct thermal_zone_of_device_ops hwmon_thermal_ops = {
d560168b5   Guenter Roeck   hwmon: (core) New...
146
147
  	.get_temp = hwmon_thermal_get_temp,
  };
1597b374a   Guenter Roeck   hwmon: Add notifi...
148
149
150
151
  static void hwmon_thermal_remove_sensor(void *data)
  {
  	list_del(data);
  }
3bf8bdcf3   Guenter Roeck   hwmon: (core) Do ...
152
  static int hwmon_thermal_add_sensor(struct device *dev, int index)
d560168b5   Guenter Roeck   hwmon: (core) New...
153
  {
1597b374a   Guenter Roeck   hwmon: Add notifi...
154
  	struct hwmon_device *hwdev = to_hwmon_device(dev);
d560168b5   Guenter Roeck   hwmon: (core) New...
155
  	struct hwmon_thermal_data *tdata;
47c332deb   Linus Walleij   hwmon: Deal with ...
156
  	struct thermal_zone_device *tzd;
1597b374a   Guenter Roeck   hwmon: Add notifi...
157
  	int err;
d560168b5   Guenter Roeck   hwmon: (core) New...
158
159
160
161
  
  	tdata = devm_kzalloc(dev, sizeof(*tdata), GFP_KERNEL);
  	if (!tdata)
  		return -ENOMEM;
3bf8bdcf3   Guenter Roeck   hwmon: (core) Do ...
162
  	tdata->dev = dev;
d560168b5   Guenter Roeck   hwmon: (core) New...
163
  	tdata->index = index;
3bf8bdcf3   Guenter Roeck   hwmon: (core) Do ...
164
  	tzd = devm_thermal_zone_of_sensor_register(dev, index, tdata,
47c332deb   Linus Walleij   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   Guenter Roeck   hwmon: (core) New...
172

1597b374a   Guenter Roeck   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   Guenter Roeck   hwmon: (core) New...
179
180
  	return 0;
  }
44e3ad882   Akinobu Mita   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   Guenter Roeck   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   Guenter Roeck   hwmon: (core) New...
224
  #else
44e3ad882   Akinobu Mita   hwmon: Reduce ind...
225
  static int hwmon_thermal_register_sensors(struct device *dev)
d560168b5   Guenter Roeck   hwmon: (core) New...
226
227
228
  {
  	return 0;
  }
1597b374a   Guenter Roeck   hwmon: Add notifi...
229
230
  
  static void hwmon_thermal_notify(struct device *dev, int index) { }
86430c1a6   Guenter Roeck   hwmon: (core) Avo...
231
  #endif /* IS_REACHABLE(CONFIG_THERMAL) && ... */
d560168b5   Guenter Roeck   hwmon: (core) New...
232

61b8ab2c5   Nicolin Chen   hwmon: (core) Add...
233
234
  static int hwmon_attr_base(enum hwmon_sensor_types type)
  {
4413405f9   Dr. David Alan Gilbert   hwmon: Add intrus...
235
  	if (type == hwmon_in || type == hwmon_intrusion)
61b8ab2c5   Nicolin Chen   hwmon: (core) Add...
236
237
238
  		return 0;
  	return 1;
  }
d560168b5   Guenter Roeck   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   Nicolin Chen   hwmon: (core) Add...
252
253
  	trace_hwmon_attr_show(hattr->index + hwmon_attr_base(hattr->type),
  			      hattr->name, val);
d560168b5   Guenter Roeck   hwmon: (core) New...
254
255
256
  	return sprintf(buf, "%ld
  ", val);
  }
e159ab5cb   Guenter Roeck   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   Nicolin Chen   hwmon: (core) Add...
262
  	enum hwmon_sensor_types type = hattr->type;
5ba6bcbc3   Jean Delvare   hwmon: Constify s...
263
  	const char *s;
e159ab5cb   Guenter Roeck   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   Nicolin Chen   hwmon: (core) Add...
270
271
  	trace_hwmon_attr_show_string(hattr->index + hwmon_attr_base(type),
  				     hattr->name, s);
e159ab5cb   Guenter Roeck   hwmon: (core) Add...
272
273
274
  	return sprintf(buf, "%s
  ", s);
  }
d560168b5   Guenter Roeck   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   Nicolin Chen   hwmon: (core) Add...
291
292
  	trace_hwmon_attr_store(hattr->index + hwmon_attr_base(hattr->type),
  			       hattr->name, val);
d560168b5   Guenter Roeck   hwmon: (core) New...
293

61b8ab2c5   Nicolin Chen   hwmon: (core) Add...
294
  	return count;
d560168b5   Guenter Roeck   hwmon: (core) New...
295
  }
e159ab5cb   Guenter Roeck   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   Guenter Roeck   hwmon: (core) Do ...
306
  static struct attribute *hwmon_genattr(const void *drvdata,
d560168b5   Guenter Roeck   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   Rasmus Villemoes   hwmon: (core) rem...
317
  	const char *name;
e159ab5cb   Guenter Roeck   hwmon: (core) Add...
318
  	bool is_string = is_string_attr(type, attr);
d560168b5   Guenter Roeck   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   Guenter Roeck   hwmon: (hwmon) Re...
327
  	if ((mode & 0444) && ((is_string && !ops->read_string) ||
e159ab5cb   Guenter Roeck   hwmon: (core) Add...
328
  				 (!is_string && !ops->read)))
d560168b5   Guenter Roeck   hwmon: (core) New...
329
  		return ERR_PTR(-EINVAL);
0d87116fe   Guenter Roeck   hwmon: (hwmon) Re...
330
  	if ((mode & 0222) && !ops->write)
d560168b5   Guenter Roeck   hwmon: (core) New...
331
  		return ERR_PTR(-EINVAL);
3bf8bdcf3   Guenter Roeck   hwmon: (core) Do ...
332
  	hattr = kzalloc(sizeof(*hattr), GFP_KERNEL);
3a412d5e4   Guenter Roeck   hwmon: (core) Sim...
333
334
  	if (!hattr)
  		return ERR_PTR(-ENOMEM);
d560168b5   Guenter Roeck   hwmon: (core) New...
335
  	if (type == hwmon_chip) {
3b443def4   Rasmus Villemoes   hwmon: (core) rem...
336
  		name = template;
d560168b5   Guenter Roeck   hwmon: (core) New...
337
  	} else {
3a412d5e4   Guenter Roeck   hwmon: (core) Sim...
338
  		scnprintf(hattr->name, sizeof(hattr->name), template,
d560168b5   Guenter Roeck   hwmon: (core) New...
339
  			  index + hwmon_attr_base(type));
3a412d5e4   Guenter Roeck   hwmon: (core) Sim...
340
  		name = hattr->name;
d560168b5   Guenter Roeck   hwmon: (core) New...
341
  	}
d560168b5   Guenter Roeck   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   Guenter Roeck   hwmon: (core) Add...
348
  	dattr->show = is_string ? hwmon_attr_show_string : hwmon_attr_show;
d560168b5   Guenter Roeck   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   Guenter Roeck   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   Guenter Roeck   hwmon: (core) New...
363
  	[hwmon_chip_temp_reset_history] = "temp_reset_history",
00d616cf8   Guenter Roeck   hwmon: (core) Add...
364
  	[hwmon_chip_in_reset_history] = "in_reset_history",
9b26947ce   Guenter Roeck   hwmon: (core) Add...
365
  	[hwmon_chip_curr_reset_history] = "curr_reset_history",
b308f5c74   Guenter Roeck   hwmon: (core) Add...
366
  	[hwmon_chip_power_reset_history] = "power_reset_history",
d560168b5   Guenter Roeck   hwmon: (core) New...
367
368
  	[hwmon_chip_update_interval] = "update_interval",
  	[hwmon_chip_alarms] = "alarms",
9f00995e4   Guenter Roeck   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   Guenter Roeck   hwmon: (core) New...
374
375
376
  };
  
  static const char * const hwmon_temp_attr_templates[] = {
002c6b545   Guenter Roeck   hwmon: Add suppor...
377
  	[hwmon_temp_enable] = "temp%d_enable",
d560168b5   Guenter Roeck   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   Zbigniew Lukwinski   hwmon: (core) Add...
402
403
  	[hwmon_temp_rated_min] = "temp%d_rated_min",
  	[hwmon_temp_rated_max] = "temp%d_rated_max",
d560168b5   Guenter Roeck   hwmon: (core) New...
404
  };
00d616cf8   Guenter Roeck   hwmon: (core) Add...
405
  static const char * const hwmon_in_attr_templates[] = {
002c6b545   Guenter Roeck   hwmon: Add suppor...
406
  	[hwmon_in_enable] = "in%d_enable",
00d616cf8   Guenter Roeck   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   Zbigniew Lukwinski   hwmon: (core) Add...
422
423
  	[hwmon_in_rated_min] = "in%d_rated_min",
  	[hwmon_in_rated_max] = "in%d_rated_max",
00d616cf8   Guenter Roeck   hwmon: (core) Add...
424
  };
9b26947ce   Guenter Roeck   hwmon: (core) Add...
425
  static const char * const hwmon_curr_attr_templates[] = {
002c6b545   Guenter Roeck   hwmon: Add suppor...
426
  	[hwmon_curr_enable] = "curr%d_enable",
9b26947ce   Guenter Roeck   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   Zbigniew Lukwinski   hwmon: (core) Add...
442
443
  	[hwmon_curr_rated_min] = "curr%d_rated_min",
  	[hwmon_curr_rated_max] = "curr%d_rated_max",
9b26947ce   Guenter Roeck   hwmon: (core) Add...
444
  };
b308f5c74   Guenter Roeck   hwmon: (core) Add...
445
  static const char * const hwmon_power_attr_templates[] = {
002c6b545   Guenter Roeck   hwmon: Add suppor...
446
  	[hwmon_power_enable] = "power%d_enable",
b308f5c74   Guenter Roeck   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   Andrew Lunn   hwmon: Add suppor...
464
  	[hwmon_power_min] = "power%d_min",
b308f5c74   Guenter Roeck   hwmon: (core) Add...
465
  	[hwmon_power_max] = "power%d_max",
aa7f29b07   Andrew Lunn   hwmon: Add suppor...
466
  	[hwmon_power_lcrit] = "power%d_lcrit",
b308f5c74   Guenter Roeck   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   Andrew Lunn   hwmon: Add suppor...
471
  	[hwmon_power_min_alarm] = "power%d_min_alarm",
b308f5c74   Guenter Roeck   hwmon: (core) Add...
472
  	[hwmon_power_max_alarm] = "power%d_max_alarm",
aa7f29b07   Andrew Lunn   hwmon: Add suppor...
473
  	[hwmon_power_lcrit_alarm] = "power%d_lcrit_alarm",
b308f5c74   Guenter Roeck   hwmon: (core) Add...
474
  	[hwmon_power_crit_alarm] = "power%d_crit_alarm",
1967f7126   Zbigniew Lukwinski   hwmon: (core) Add...
475
476
  	[hwmon_power_rated_min] = "power%d_rated_min",
  	[hwmon_power_rated_max] = "power%d_rated_max",
b308f5c74   Guenter Roeck   hwmon: (core) Add...
477
  };
6bfcca44a   Guenter Roeck   hwmon: (core) Add...
478
  static const char * const hwmon_energy_attr_templates[] = {
002c6b545   Guenter Roeck   hwmon: Add suppor...
479
  	[hwmon_energy_enable] = "energy%d_enable",
6bfcca44a   Guenter Roeck   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   Guenter Roeck   hwmon: Add suppor...
485
  	[hwmon_humidity_enable] = "humidity%d_enable",
6bfcca44a   Guenter Roeck   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   Zbigniew Lukwinski   hwmon: (core) Add...
494
495
  	[hwmon_humidity_rated_min] = "humidity%d_rated_min",
  	[hwmon_humidity_rated_max] = "humidity%d_rated_max",
6bfcca44a   Guenter Roeck   hwmon: (core) Add...
496
  };
8faee73f9   Guenter Roeck   hwmon: (core) Add...
497
  static const char * const hwmon_fan_attr_templates[] = {
002c6b545   Guenter Roeck   hwmon: Add suppor...
498
  	[hwmon_fan_enable] = "fan%d_enable",
8faee73f9   Guenter Roeck   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   Guenter Roeck   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   Dr. David Alan Gilbert   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   Guenter Roeck   hwmon: (core) New...
521
  static const char * const *__templates[] = {
f4d325d5e   Guenter Roeck   hwmon: (core) Cla...
522
  	[hwmon_chip] = hwmon_chip_attrs,
d560168b5   Guenter Roeck   hwmon: (core) New...
523
  	[hwmon_temp] = hwmon_temp_attr_templates,
00d616cf8   Guenter Roeck   hwmon: (core) Add...
524
  	[hwmon_in] = hwmon_in_attr_templates,
9b26947ce   Guenter Roeck   hwmon: (core) Add...
525
  	[hwmon_curr] = hwmon_curr_attr_templates,
b308f5c74   Guenter Roeck   hwmon: (core) Add...
526
  	[hwmon_power] = hwmon_power_attr_templates,
6bfcca44a   Guenter Roeck   hwmon: (core) Add...
527
528
  	[hwmon_energy] = hwmon_energy_attr_templates,
  	[hwmon_humidity] = hwmon_humidity_attr_templates,
8faee73f9   Guenter Roeck   hwmon: (core) Add...
529
  	[hwmon_fan] = hwmon_fan_attr_templates,
f9f7bb3a0   Guenter Roeck   hwmon: (core) Add...
530
  	[hwmon_pwm] = hwmon_pwm_attr_templates,
4413405f9   Dr. David Alan Gilbert   hwmon: Add intrus...
531
  	[hwmon_intrusion] = hwmon_intrusion_attr_templates,
d560168b5   Guenter Roeck   hwmon: (core) New...
532
533
534
  };
  
  static const int __templates_size[] = {
f4d325d5e   Guenter Roeck   hwmon: (core) Cla...
535
  	[hwmon_chip] = ARRAY_SIZE(hwmon_chip_attrs),
d560168b5   Guenter Roeck   hwmon: (core) New...
536
  	[hwmon_temp] = ARRAY_SIZE(hwmon_temp_attr_templates),
00d616cf8   Guenter Roeck   hwmon: (core) Add...
537
  	[hwmon_in] = ARRAY_SIZE(hwmon_in_attr_templates),
9b26947ce   Guenter Roeck   hwmon: (core) Add...
538
  	[hwmon_curr] = ARRAY_SIZE(hwmon_curr_attr_templates),
b308f5c74   Guenter Roeck   hwmon: (core) Add...
539
  	[hwmon_power] = ARRAY_SIZE(hwmon_power_attr_templates),
6bfcca44a   Guenter Roeck   hwmon: (core) Add...
540
541
  	[hwmon_energy] = ARRAY_SIZE(hwmon_energy_attr_templates),
  	[hwmon_humidity] = ARRAY_SIZE(hwmon_humidity_attr_templates),
8faee73f9   Guenter Roeck   hwmon: (core) Add...
542
  	[hwmon_fan] = ARRAY_SIZE(hwmon_fan_attr_templates),
f9f7bb3a0   Guenter Roeck   hwmon: (core) Add...
543
  	[hwmon_pwm] = ARRAY_SIZE(hwmon_pwm_attr_templates),
4413405f9   Dr. David Alan Gilbert   hwmon: Add intrus...
544
  	[hwmon_intrusion] = ARRAY_SIZE(hwmon_intrusion_attr_templates),
d560168b5   Guenter Roeck   hwmon: (core) New...
545
  };
1597b374a   Guenter Roeck   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   Guenter Roeck   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   Guenter Roeck   hwmon: (core) Do ...
583
  static int hwmon_genattrs(const void *drvdata,
d560168b5   Guenter Roeck   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   Guenter Roeck   hwmon: (core) Do ...
609
  			a = hwmon_genattr(drvdata, info->type, attr, i,
d560168b5   Guenter Roeck   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   Guenter Roeck   hwmon: (core) Do ...
623
  __hwmon_create_attrs(const void *drvdata, const struct hwmon_chip_info *chip)
d560168b5   Guenter Roeck   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   Guenter Roeck   hwmon: (core) Do ...
633
  	attrs = kcalloc(nattrs + 1, sizeof(*attrs), GFP_KERNEL);
d560168b5   Guenter Roeck   hwmon: (core) New...
634
635
636
637
  	if (!attrs)
  		return ERR_PTR(-ENOMEM);
  
  	for (i = 0; chip->info[i]; i++) {
3bf8bdcf3   Guenter Roeck   hwmon: (core) Do ...
638
  		ret = hwmon_genattrs(drvdata, &attrs[aindex], chip->ops,
d560168b5   Guenter Roeck   hwmon: (core) New...
639
  				     chip->info[i]);
3bf8bdcf3   Guenter Roeck   hwmon: (core) Do ...
640
641
  		if (ret < 0) {
  			hwmon_free_attrs(attrs);
d560168b5   Guenter Roeck   hwmon: (core) New...
642
  			return ERR_PTR(ret);
3bf8bdcf3   Guenter Roeck   hwmon: (core) Do ...
643
  		}
d560168b5   Guenter Roeck   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   Mark M. Hoffman   [PATCH] I2C hwmon...
654
  {
bab2243ce   Guenter Roeck   hwmon: Introduce ...
655
  	struct hwmon_device *hwdev;
d560168b5   Guenter Roeck   hwmon: (core) New...
656
  	struct device *hdev;
44e3ad882   Akinobu Mita   hwmon: Reduce ind...
657
  	int i, err, id;
ded2b6661   Mark M. Hoffman   [PATCH] hwmon: ad...
658

74d3b6419   Guenter Roeck   hwmon: Relax name...
659
  	/* Complain about invalid characters in hwmon name attribute */
648cd48c9   Guenter Roeck   hwmon: Do not acc...
660
661
  	if (name && (!strlen(name) || strpbrk(name, "-* \t
  ")))
74d3b6419   Guenter Roeck   hwmon: Relax name...
662
663
664
665
  		dev_warn(dev,
  			 "hwmon: '%s' is not a valid name attribute, please fix
  ",
  			 name);
648cd48c9   Guenter Roeck   hwmon: Do not acc...
666

4ca5f468c   Jonathan Cameron   hwmon: convert id...
667
668
669
  	id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL);
  	if (id < 0)
  		return ERR_PTR(id);
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
670

bab2243ce   Guenter Roeck   hwmon: Introduce ...
671
672
673
674
675
  	hwdev = kzalloc(sizeof(*hwdev), GFP_KERNEL);
  	if (hwdev == NULL) {
  		err = -ENOMEM;
  		goto ida_remove;
  	}
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
676

d560168b5   Guenter Roeck   hwmon: (core) New...
677
  	hdev = &hwdev->dev;
239552f49   Guenter Roeck   hwmon: (core) Mak...
678
  	if (chip) {
d560168b5   Guenter Roeck   hwmon: (core) New...
679
  		struct attribute **attrs;
b2a4cc3a0   Guenter Roeck   hwmon: (core) Exp...
680
  		int ngroups = 2; /* terminating NULL plus &hwdev->groups */
d560168b5   Guenter Roeck   hwmon: (core) New...
681
682
683
684
  
  		if (groups)
  			for (i = 0; groups[i]; i++)
  				ngroups++;
3bf8bdcf3   Guenter Roeck   hwmon: (core) Do ...
685
  		hwdev->groups = kcalloc(ngroups, sizeof(*groups), GFP_KERNEL);
38d8ed650   Colin Ian King   hwmon: (core) fix...
686
687
688
689
  		if (!hwdev->groups) {
  			err = -ENOMEM;
  			goto free_hwmon;
  		}
d560168b5   Guenter Roeck   hwmon: (core) New...
690

3bf8bdcf3   Guenter Roeck   hwmon: (core) Do ...
691
  		attrs = __hwmon_create_attrs(drvdata, chip);
d560168b5   Guenter Roeck   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   Guenter Roeck   hwmon: Introduce ...
710
  	hwdev->name = name;
d560168b5   Guenter Roeck   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   Guenter Roeck   hwmon: Introduce ...
718
  	if (err)
d560168b5   Guenter Roeck   hwmon: (core) New...
719
  		goto free_hwmon;
1597b374a   Guenter Roeck   hwmon: Add notifi...
720
  	INIT_LIST_HEAD(&hwdev->tzdata);
c41dd48e2   Eduardo Valentin   hwmon: (core) add...
721
  	if (dev && dev->of_node && chip && chip->ops->read &&
d560168b5   Guenter Roeck   hwmon: (core) New...
722
723
  	    chip->info[0]->type == hwmon_chip &&
  	    (chip->info[0]->config[0] & HWMON_C_REGISTER_TZ)) {
44e3ad882   Akinobu Mita   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   Guenter Roeck   hwmon: (core) New...
732
733
  		}
  	}
bab2243ce   Guenter Roeck   hwmon: Introduce ...
734

d560168b5   Guenter Roeck   hwmon: (core) New...
735
  	return hdev;
bab2243ce   Guenter Roeck   hwmon: Introduce ...
736

d560168b5   Guenter Roeck   hwmon: (core) New...
737
  free_hwmon:
3bf8bdcf3   Guenter Roeck   hwmon: (core) Do ...
738
  	hwmon_dev_release(hdev);
bab2243ce   Guenter Roeck   hwmon: Introduce ...
739
740
741
742
  ida_remove:
  	ida_simple_remove(&hwmon_ida, id);
  	return ERR_PTR(err);
  }
d560168b5   Guenter Roeck   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   Guenter Roeck   hwmon: Make name ...
761
762
  	if (!name)
  		return ERR_PTR(-EINVAL);
d560168b5   Guenter Roeck   hwmon: (core) New...
763
764
  	return __hwmon_device_register(dev, name, drvdata, NULL, groups);
  }
bab2243ce   Guenter Roeck   hwmon: Introduce ...
765
  EXPORT_SYMBOL_GPL(hwmon_device_register_with_groups);
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
766

bab2243ce   Guenter Roeck   hwmon: Introduce ...
767
  /**
d560168b5   Guenter Roeck   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   Guenter Roeck   hwmon: Fix parame...
772
   * @chip: pointer to hwmon chip information
848ba0a2f   Guenter Roeck   hwmon: (core) Ren...
773
   * @extra_groups: pointer to list of additional non-standard attribute groups
d560168b5   Guenter Roeck   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   Guenter Roeck   hwmon: (core) Ren...
784
  				const struct attribute_group **extra_groups)
d560168b5   Guenter Roeck   hwmon: (core) New...
785
  {
8353863a5   Guenter Roeck   hwmon: Make name ...
786
787
  	if (!name)
  		return ERR_PTR(-EINVAL);
239552f49   Guenter Roeck   hwmon: (core) Mak...
788
  	if (chip && (!chip->ops || !chip->ops->is_visible || !chip->info))
d560168b5   Guenter Roeck   hwmon: (core) New...
789
  		return ERR_PTR(-EINVAL);
59df4f4e8   Lucas Magasweran   hwmon: (core) che...
790
791
  	if (chip && !dev)
  		return ERR_PTR(-EINVAL);
848ba0a2f   Guenter Roeck   hwmon: (core) Ren...
792
  	return __hwmon_device_register(dev, name, drvdata, chip, extra_groups);
d560168b5   Guenter Roeck   hwmon: (core) New...
793
794
795
796
  }
  EXPORT_SYMBOL_GPL(hwmon_device_register_with_info);
  
  /**
bab2243ce   Guenter Roeck   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   Guenter Roeck   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   Guenter Roeck   hwmon: Make name ...
810
  	return __hwmon_device_register(dev, NULL, NULL, NULL, NULL);
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
811
  }
839a9eefc   Frans Meulenbroeks   hwmon: fix checkp...
812
  EXPORT_SYMBOL_GPL(hwmon_device_register);
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
813
814
815
816
  
  /**
   * hwmon_device_unregister - removes the previously registered class device
   *
1beeffe43   Tony Jones   hwmon: Convert fr...
817
   * @dev: the class device to destroy
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
818
   */
1beeffe43   Tony Jones   hwmon: Convert fr...
819
  void hwmon_device_unregister(struct device *dev)
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
820
821
  {
  	int id;
739cf3a26   Kay Sievers   hwmon: struct dev...
822
  	if (likely(sscanf(dev_name(dev), HWMON_ID_FORMAT, &id) == 1)) {
1beeffe43   Tony Jones   hwmon: Convert fr...
823
  		device_unregister(dev);
4ca5f468c   Jonathan Cameron   hwmon: convert id...
824
  		ida_simple_remove(&hwmon_ida, id);
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
825
  	} else
1beeffe43   Tony Jones   hwmon: Convert fr...
826
  		dev_dbg(dev->parent,
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
827
828
829
  			"hwmon_device_unregister() failed: bad class ID!
  ");
  }
839a9eefc   Frans Meulenbroeks   hwmon: fix checkp...
830
  EXPORT_SYMBOL_GPL(hwmon_device_unregister);
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
831

74188cba0   Guenter Roeck   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   Guenter Roeck   hwmon: (core) New...
876
877
  /**
   * devm_hwmon_device_register_with_info - register w/ hwmon
3870945ae   Guenter Roeck   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   Guenter Roeck   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   Guenter Roeck   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   Jean Delvare   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   Jean Delvare   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   Jean Delvare   hwmon: PCI quirk ...
957
  		}
d6dab7dd1   Jean Delvare   hwmon: Fix PCI de...
958
  		pci_dev_put(sb);
2958b1ec6   Jean Delvare   hwmon: PCI quirk ...
959
960
961
  	}
  #endif
  }
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
962
963
  static int __init hwmon_init(void)
  {
bab2243ce   Guenter Roeck   hwmon: Introduce ...
964
  	int err;
2958b1ec6   Jean Delvare   hwmon: PCI quirk ...
965
  	hwmon_pci_quirks();
bab2243ce   Guenter Roeck   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   Mark M. Hoffman   [PATCH] I2C hwmon...
971
972
973
974
975
976
  	}
  	return 0;
  }
  
  static void __exit hwmon_exit(void)
  {
bab2243ce   Guenter Roeck   hwmon: Introduce ...
977
  	class_unregister(&hwmon_class);
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
978
  }
37f54ee54   David Brownell   hwmon: Use subsys...
979
  subsys_initcall(hwmon_init);
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
980
  module_exit(hwmon_exit);
1236441f3   Mark M. Hoffman   [PATCH] I2C hwmon...
981
982
983
  MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
  MODULE_DESCRIPTION("hardware monitoring sysfs/class support");
  MODULE_LICENSE("GPL");