blob: b7b1297a9b02c5027d0374e7fd9baf0896c1dcb5 [file] [log] [blame]
Shivaprasad G Bhat0de7f8a2014-03-07 11:03:39 +05301/*
2 * hwmon driver for temperature/power/fan on IBM PowerNV platform
3 * Copyright (C) 2013 IBM
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#include <linux/init.h>
21#include <linux/module.h>
22#include <linux/kernel.h>
23#include <linux/hwmon.h>
24#include <linux/hwmon-sysfs.h>
25#include <linux/of.h>
26#include <linux/slab.h>
27
28#include <linux/jiffies.h>
29#include <linux/platform_device.h>
30#include <asm/opal.h>
31#include <linux/err.h>
32
33MODULE_DESCRIPTION("IBM PowerNV Platform power/temp/fan sensor hwmon module");
34MODULE_LICENSE("GPL");
35
36#define MAX_ATTR_LENGTH 32
37
38/* Device tree sensor name prefixes. The device tree has the names in the
39 * format "cooling-fan#2-faulted" where the "cooling-fan" is the sensor type,
40 * 2 is the sensor count, and "faulted" is the sensor data attribute type.
41 */
42#define DT_FAULT_ATTR_SUFFIX "faulted"
43#define DT_DATA_ATTR_SUFFIX "data"
44#define DT_THRESHOLD_ATTR_SUFFIX "thrs"
45
46enum sensors {
47 FAN,
48 TEMPERATURE,
49 POWERSUPPLY,
50 POWER,
51 MAX_SENSOR_TYPE,
52};
53
54enum attributes {
55 INPUT,
56 MINIMUM,
57 MAXIMUM,
58 FAULT,
59 MAX_ATTR_TYPES
60};
61
62static struct sensor_name {
63 char *name;
64 char *compaible;
65} sensor_names[] = {
66 {"fan-sensor", "ibm,opal-sensor-cooling-fan"},
67 {"amb-temp-sensor", "ibm,opal-sensor-amb-temp"},
68 {"power-sensor", "ibm,opal-sensor-power-supply"},
69 {"power", "ibm,opal-sensor-power"}
70};
71
72static const char * const attribute_type_table[] = {
73 "input",
74 "min",
75 "max",
76 "fault",
77 NULL
78};
79
80struct pdev_entry {
81 struct list_head list;
82 struct platform_device *pdev;
83 enum sensors type;
84};
85
86static LIST_HEAD(pdev_list);
87
88/* The sensors are categorised on type.
89 *
90 * The sensors of same type are categorised under a common platform device.
91 * So, The pdev is shared by all sensors of same type.
92 * Ex : temp1_input, temp1_max, temp2_input,temp2_max all share same platform
93 * device.
94 *
95 * "sensor_data" is the Platform device specific data.
96 * There is one hwmon_device instance for all the sensors of same type.
97 * This also holds the list of all sensors with same type but different
98 * attribute and index.
99 */
100struct sensor_specific_data {
101 u32 sensor_id; /* The hex value as in the device tree */
102 u32 sensor_index; /* The sensor instance index */
103 struct sensor_device_attribute sd_attr;
104 enum attributes attr_type;
105 char attr_name[64];
106};
107
108struct sensor_data {
109 struct device *hwmon_dev;
110 struct list_head sensor_list;
111 struct device_attribute name_attr;
112};
113
114struct sensor_entry {
115 struct list_head list;
116 struct sensor_specific_data *sensor_data;
117};
118
119static struct platform_device *powernv_sensor_get_pdev(enum sensors type)
120{
121 struct pdev_entry *p;
122 list_for_each_entry(p, &pdev_list, list)
123 if (p->type == type)
124 return p->pdev;
125
126 return NULL;
127}
128
129static struct sensor_specific_data *powernv_sensor_get_sensor_data(
130 struct sensor_data *pdata,
131 int index, enum attributes attr_type)
132{
133 struct sensor_entry *p;
134 list_for_each_entry(p, &pdata->sensor_list, list)
135 if ((p->sensor_data->sensor_index == index) &&
136 (attr_type == p->sensor_data->attr_type))
137 return p->sensor_data;
138
139 return NULL;
140}
141
142static ssize_t show_name(struct device *dev,
143 struct device_attribute *devattr, char *buf)
144{
145 struct platform_device *pdev = to_platform_device(dev);
146
147 return sprintf(buf, "%s\n", pdev->name);
148}
149
150/* Note: Data from the sensors for each sensor type needs to be converted to
151 * the dimension appropriate.
152 */
153static ssize_t show_sensor(struct device *dev,
154 struct device_attribute *devattr, char *buf)
155{
156 struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(devattr);
157 struct platform_device *pdev = to_platform_device(dev);
158 struct sensor_data *pdata = platform_get_drvdata(pdev);
159 struct sensor_specific_data *tdata = NULL;
160 enum sensors sensor_type = pdev->id;
161 u32 x = -1;
162 int ret;
163
164 if (sd_attr && sd_attr->dev_attr.attr.name) {
165 char *pos = strchr(sd_attr->dev_attr.attr.name, '_');
166 int i;
167
168 for (i = 0; i < MAX_ATTR_TYPES; i++) {
169 if (strcmp(pos+1, attribute_type_table[i]) == 0) {
170 tdata = powernv_sensor_get_sensor_data(pdata,
171 sd_attr->index, i);
172 break;
173 }
174 }
175 }
176
177 if (tdata) {
178 ret = opal_get_sensor_data(tdata->sensor_id, &x);
179 if (ret)
180 x = -1;
181 }
182
183 if (sensor_type == TEMPERATURE && x > 0) {
184 /* Temperature comes in Degrees and convert it to
185 * milli-degrees.
186 */
187 x = x*1000;
188 } else if (sensor_type == POWER && x > 0) {
189 /* Power value comes in watts, convert to micro-watts */
190 x = x * 1000000;
191 }
192
193 return sprintf(buf, "%d\n", x);
194}
195
196static u32 get_sensor_index_from_name(const char *name)
197{
198 char *hash_position = strchr(name, '#');
199 u32 index = 0, copy_length;
200 char newbuf[8];
201
202 if (hash_position) {
203 copy_length = strchr(hash_position, '-') - hash_position - 1;
204 if (copy_length < sizeof(newbuf)) {
205 strncpy(newbuf, hash_position + 1, copy_length);
206 sscanf(newbuf, "%d", &index);
207 }
208 }
209
210 return index;
211}
212
213static inline void get_sensor_suffix_from_name(const char *name, char *suffix)
214{
215 char *dash_position = strrchr(name, '-');
216 if (dash_position)
217 strncpy(suffix, dash_position+1, MAX_ATTR_LENGTH);
218 else
219 strcpy(suffix,"");
220}
221
222static int get_sensor_attr_properties(const char *sensor_name,
223 enum sensors sensor_type, enum attributes *attr_type,
224 u32 *sensor_index)
225{
226 char suffix[MAX_ATTR_LENGTH];
227
228 *attr_type = MAX_ATTR_TYPES;
229 *sensor_index = get_sensor_index_from_name(sensor_name);
230 if (*sensor_index == 0)
231 return -EINVAL;
232
233 get_sensor_suffix_from_name(sensor_name, suffix);
234 if (strcmp(suffix, "") == 0)
235 return -EINVAL;
236
237 if (strcmp(suffix, DT_FAULT_ATTR_SUFFIX) == 0)
238 *attr_type = FAULT;
239 else if (strcmp(suffix, DT_DATA_ATTR_SUFFIX) == 0)
240 *attr_type = INPUT;
241 else if ((sensor_type == TEMPERATURE) &&
242 (strcmp(suffix, DT_THRESHOLD_ATTR_SUFFIX) == 0))
243 *attr_type = MAXIMUM;
244 else if ((sensor_type == FAN) &&
245 (strcmp(suffix, DT_THRESHOLD_ATTR_SUFFIX) == 0))
246 *attr_type = MINIMUM;
247 else
248 return -ENOENT;
249
250 if (((sensor_type == FAN) && ((*attr_type == INPUT) ||
251 (*attr_type == MINIMUM)))
252 || ((sensor_type == TEMPERATURE) && ((*attr_type == INPUT) ||
253 (*attr_type == MAXIMUM)))
254 || ((sensor_type == POWER) && ((*attr_type == INPUT))))
255 return 0;
256
257 return -ENOENT;
258}
259
260static int create_sensor_attr(struct sensor_specific_data *tdata,
261 struct device *dev, enum sensors sensor_type,
262 enum attributes attr_type)
263{
264 int err = 0;
265 char temp_file_prefix[50];
266 static const char *const file_name_format = "%s%d_%s";
267
268 tdata->attr_type = attr_type;
269
270 if (sensor_type == FAN)
271 strcpy(temp_file_prefix, "fan");
272 else if (sensor_type == TEMPERATURE)
273 strcpy(temp_file_prefix, "temp");
274 else if (sensor_type == POWERSUPPLY)
275 strcpy(temp_file_prefix, "powersupply");
276 else if (sensor_type == POWER)
277 strcpy(temp_file_prefix, "power");
278
279 snprintf(tdata->attr_name, sizeof(tdata->attr_name), file_name_format,
280 temp_file_prefix, tdata->sensor_index,
281 attribute_type_table[tdata->attr_type]);
282
283 sysfs_attr_init(&tdata->sd_attr.dev_attr.attr);
284 tdata->sd_attr.dev_attr.attr.name = tdata->attr_name;
285 tdata->sd_attr.dev_attr.attr.mode = S_IRUGO;
286 tdata->sd_attr.dev_attr.show = show_sensor;
287
288 tdata->sd_attr.index = tdata->sensor_index;
289 err = device_create_file(dev, &tdata->sd_attr.dev_attr);
290
291 return err;
292}
293
294static int create_name_attr(struct sensor_data *pdata,
295 struct device *dev)
296{
297 sysfs_attr_init(&pdata->name_attr.attr);
298 pdata->name_attr.attr.name = "name";
299 pdata->name_attr.attr.mode = S_IRUGO;
300 pdata->name_attr.show = show_name;
301 return device_create_file(dev, &pdata->name_attr);
302}
303
304static int create_platform_device(enum sensors sensor_type,
305 struct platform_device **pdev)
306{
307 struct pdev_entry *pdev_entry = NULL;
308 int err;
309
310 *pdev = platform_device_alloc(sensor_names[sensor_type].name,
311 sensor_type);
312 if (!*pdev) {
313 pr_err("Device allocation failed\n");
314 err = -ENOMEM;
315 goto exit;
316 }
317
318 pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL);
319 if (!pdev_entry) {
320 pr_err("Device allocation failed\n");
321 err = -ENOMEM;
322 goto exit_device_put;
323 }
324
325 err = platform_device_add(*pdev);
326 if (err) {
327 pr_err("Device addition failed (%d)\n", err);
328 goto exit_device_free;
329 }
330
331 pdev_entry->pdev = *pdev;
332 pdev_entry->type = (*pdev)->id;
333
334 list_add_tail(&pdev_entry->list, &pdev_list);
335
336 return 0;
337exit_device_free:
338 kfree(pdev_entry);
339exit_device_put:
340 platform_device_put(*pdev);
341exit:
342 return err;
343}
344
345static int create_sensor_data(struct platform_device *pdev)
346{
347 struct sensor_data *pdata = NULL;
348 int err = 0;
349
350 pdata = kzalloc(sizeof(struct sensor_data), GFP_KERNEL);
351 if (!pdata) {
352 err = -ENOMEM;
353 goto exit;
354 }
355
356 err = create_name_attr(pdata, &pdev->dev);
357 if (err)
358 goto exit_free;
359
360 pdata->hwmon_dev = hwmon_device_register(&pdev->dev);
361 if (IS_ERR(pdata->hwmon_dev)) {
362 err = PTR_ERR(pdata->hwmon_dev);
363 dev_err(&pdev->dev, "Class registration failed (%d)\n",
364 err);
365 goto exit_name;
366 }
367
368 INIT_LIST_HEAD(&pdata->sensor_list);
369 platform_set_drvdata(pdev, pdata);
370
371 return 0;
372
373exit_name:
374 device_remove_file(&pdev->dev, &pdata->name_attr);
375exit_free:
376 kfree(pdata);
377exit:
378 return err;
379}
380
381static void delete_sensor_attr(struct sensor_data *pdata)
382{
383 struct sensor_entry *s, *l;
384
385 list_for_each_entry_safe(s, l, &pdata->sensor_list, list) {
386 struct sensor_specific_data *tdata = s->sensor_data;
387 kfree(tdata);
388 list_del(&s->list);
389 kfree(s);
390 }
391}
392
393static int powernv_sensor_init(u32 sensor_id, const struct device_node *np,
394 enum sensors sensor_type, enum attributes attr_type,
395 u32 sensor_index)
396{
397 struct platform_device *pdev = powernv_sensor_get_pdev(sensor_type);
398 struct sensor_specific_data *tdata;
399 struct sensor_entry *sensor_entry;
400 struct sensor_data *pdata;
401 int err = 0;
402
403 if (!pdev) {
404 err = create_platform_device(sensor_type, &pdev);
405 if (err)
406 goto exit;
407
408 err = create_sensor_data(pdev);
409 if (err)
410 goto exit;
411 }
412
413 pdata = platform_get_drvdata(pdev);
414 if (!pdata) {
415 err = -ENOMEM;
416 goto exit;
417 }
418
419 tdata = kzalloc(sizeof(struct sensor_specific_data), GFP_KERNEL);
420 if (!tdata) {
421 err = -ENOMEM;
422 goto exit;
423 }
424
425 tdata->sensor_id = sensor_id;
426 tdata->sensor_index = sensor_index;
427
428 err = create_sensor_attr(tdata, &pdev->dev, sensor_type, attr_type);
429 if (err)
430 goto exit_free;
431
432 sensor_entry = kzalloc(sizeof(struct sensor_entry), GFP_KERNEL);
433 if (!sensor_entry) {
434 err = -ENOMEM;
435 goto exit_attr;
436 }
437
438 sensor_entry->sensor_data = tdata;
439
440 list_add_tail(&sensor_entry->list, &pdata->sensor_list);
441
442 return 0;
443exit_attr:
444 device_remove_file(&pdev->dev, &tdata->sd_attr.dev_attr);
445exit_free:
446 kfree(tdata);
447exit:
448 return err;
449}
450
451static void delete_unregister_sensors(void)
452{
453 struct pdev_entry *p, *n;
454
455 list_for_each_entry_safe(p, n, &pdev_list, list) {
456 struct sensor_data *pdata = platform_get_drvdata(p->pdev);
457 if (pdata) {
458 delete_sensor_attr(pdata);
459
460 hwmon_device_unregister(pdata->hwmon_dev);
461 kfree(pdata);
462 }
463 platform_device_unregister(p->pdev);
464 list_del(&p->list);
465 kfree(p);
466 }
467}
468
469static int __init powernv_hwmon_init(void)
470{
471 struct device_node *opal, *np = NULL;
472 enum attributes attr_type;
473 enum sensors type;
474 const u32 *sensor_id;
475 u32 sensor_index;
476 int err;
477
478 opal = of_find_node_by_path("/ibm,opal/sensors");
479 if (!opal) {
480 pr_err("%s: Opal 'sensors' node not found\n", __func__);
481 return -ENXIO;
482 }
483
484 for_each_child_of_node(opal, np) {
485 if (np->name == NULL)
486 continue;
487
488 for (type = 0; type < MAX_SENSOR_TYPE; type++)
489 if (of_device_is_compatible(np,
490 sensor_names[type].compaible))
491 break;
492
493 if (type == MAX_SENSOR_TYPE)
494 continue;
495
496 if (get_sensor_attr_properties(np->name, type, &attr_type,
497 &sensor_index))
498 continue;
499
500 sensor_id = of_get_property(np, "sensor-id", NULL);
501 if (!sensor_id) {
502 pr_info("%s: %s doesn't have sensor-id\n", __func__,
503 np->name);
504 continue;
505 }
506
507 err = powernv_sensor_init(*sensor_id, np, type, attr_type,
508 sensor_index);
509 if (err) {
510 of_node_put(opal);
511 goto exit;
512 }
513 }
514 of_node_put(opal);
515
516 return 0;
517exit:
518 delete_unregister_sensors();
519 return err;
520
521}
522
523static void powernv_hwmon_exit(void)
524{
525 delete_unregister_sensors();
526}
527
528module_init(powernv_hwmon_init);
529module_exit(powernv_hwmon_exit);