treewide: devm_kzalloc() -> devm_kcalloc()
[linux-2.6-microblaze.git] / drivers / hwmon / ibmpowernv.c
1 /*
2  * IBM PowerNV platform sensors for temperature/fan/voltage/power
3  * Copyright (C) 2014 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.
17  */
18
19 #define DRVNAME         "ibmpowernv"
20 #define pr_fmt(fmt)     DRVNAME ": " fmt
21
22 #include <linux/init.h>
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/hwmon.h>
26 #include <linux/hwmon-sysfs.h>
27 #include <linux/of.h>
28 #include <linux/slab.h>
29
30 #include <linux/platform_device.h>
31 #include <asm/opal.h>
32 #include <linux/err.h>
33 #include <asm/cputhreads.h>
34 #include <asm/smp.h>
35
36 #define MAX_ATTR_LEN    32
37 #define MAX_LABEL_LEN   64
38
39 /* Sensor suffix name from DT */
40 #define DT_FAULT_ATTR_SUFFIX            "faulted"
41 #define DT_DATA_ATTR_SUFFIX             "data"
42 #define DT_THRESHOLD_ATTR_SUFFIX        "thrs"
43
44 /*
45  * Enumerates all the types of sensors in the POWERNV platform and does index
46  * into 'struct sensor_group'
47  */
48 enum sensors {
49         FAN,
50         TEMP,
51         POWER_SUPPLY,
52         POWER_INPUT,
53         CURRENT,
54         ENERGY,
55         MAX_SENSOR_TYPE,
56 };
57
58 #define INVALID_INDEX (-1U)
59
60 /*
61  * 'compatible' string properties for sensor types as defined in old
62  * PowerNV firmware (skiboot). These are ordered as 'enum sensors'.
63  */
64 static const char * const legacy_compatibles[] = {
65         "ibm,opal-sensor-cooling-fan",
66         "ibm,opal-sensor-amb-temp",
67         "ibm,opal-sensor-power-supply",
68         "ibm,opal-sensor-power"
69 };
70
71 static struct sensor_group {
72         const char *name; /* matches property 'sensor-type' */
73         struct attribute_group group;
74         u32 attr_count;
75         u32 hwmon_index;
76 } sensor_groups[] = {
77         { "fan"   },
78         { "temp"  },
79         { "in"    },
80         { "power" },
81         { "curr"  },
82         { "energy" },
83 };
84
85 struct sensor_data {
86         u32 id; /* An opaque id of the firmware for each sensor */
87         u32 hwmon_index;
88         u32 opal_index;
89         enum sensors type;
90         char label[MAX_LABEL_LEN];
91         char name[MAX_ATTR_LEN];
92         struct device_attribute dev_attr;
93 };
94
95 struct platform_data {
96         const struct attribute_group *attr_groups[MAX_SENSOR_TYPE + 1];
97         u32 sensors_count; /* Total count of sensors from each group */
98 };
99
100 static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr,
101                            char *buf)
102 {
103         struct sensor_data *sdata = container_of(devattr, struct sensor_data,
104                                                  dev_attr);
105         ssize_t ret;
106         u64 x;
107
108         ret =  opal_get_sensor_data_u64(sdata->id, &x);
109
110         if (ret)
111                 return ret;
112
113         /* Convert temperature to milli-degrees */
114         if (sdata->type == TEMP)
115                 x *= 1000;
116         /* Convert power to micro-watts */
117         else if (sdata->type == POWER_INPUT)
118                 x *= 1000000;
119
120         return sprintf(buf, "%llu\n", x);
121 }
122
123 static ssize_t show_label(struct device *dev, struct device_attribute *devattr,
124                           char *buf)
125 {
126         struct sensor_data *sdata = container_of(devattr, struct sensor_data,
127                                                  dev_attr);
128
129         return sprintf(buf, "%s\n", sdata->label);
130 }
131
132 static int __init get_logical_cpu(int hwcpu)
133 {
134         int cpu;
135
136         for_each_possible_cpu(cpu)
137                 if (get_hard_smp_processor_id(cpu) == hwcpu)
138                         return cpu;
139
140         return -ENOENT;
141 }
142
143 static void __init make_sensor_label(struct device_node *np,
144                                      struct sensor_data *sdata,
145                                      const char *label)
146 {
147         u32 id;
148         size_t n;
149
150         n = snprintf(sdata->label, sizeof(sdata->label), "%s", label);
151
152         /*
153          * Core temp pretty print
154          */
155         if (!of_property_read_u32(np, "ibm,pir", &id)) {
156                 int cpuid = get_logical_cpu(id);
157
158                 if (cpuid >= 0)
159                         /*
160                          * The digital thermal sensors are associated
161                          * with a core.
162                          */
163                         n += snprintf(sdata->label + n,
164                                       sizeof(sdata->label) - n, " %d",
165                                       cpuid);
166                 else
167                         n += snprintf(sdata->label + n,
168                                       sizeof(sdata->label) - n, " phy%d", id);
169         }
170
171         /*
172          * Membuffer pretty print
173          */
174         if (!of_property_read_u32(np, "ibm,chip-id", &id))
175                 n += snprintf(sdata->label + n, sizeof(sdata->label) - n,
176                               " %d", id & 0xffff);
177 }
178
179 static int get_sensor_index_attr(const char *name, u32 *index, char *attr)
180 {
181         char *hash_pos = strchr(name, '#');
182         char buf[8] = { 0 };
183         char *dash_pos;
184         u32 copy_len;
185         int err;
186
187         if (!hash_pos)
188                 return -EINVAL;
189
190         dash_pos = strchr(hash_pos, '-');
191         if (!dash_pos)
192                 return -EINVAL;
193
194         copy_len = dash_pos - hash_pos - 1;
195         if (copy_len >= sizeof(buf))
196                 return -EINVAL;
197
198         strncpy(buf, hash_pos + 1, copy_len);
199
200         err = kstrtou32(buf, 10, index);
201         if (err)
202                 return err;
203
204         strncpy(attr, dash_pos + 1, MAX_ATTR_LEN);
205
206         return 0;
207 }
208
209 static const char *convert_opal_attr_name(enum sensors type,
210                                           const char *opal_attr)
211 {
212         const char *attr_name = NULL;
213
214         if (!strcmp(opal_attr, DT_FAULT_ATTR_SUFFIX)) {
215                 attr_name = "fault";
216         } else if (!strcmp(opal_attr, DT_DATA_ATTR_SUFFIX)) {
217                 attr_name = "input";
218         } else if (!strcmp(opal_attr, DT_THRESHOLD_ATTR_SUFFIX)) {
219                 if (type == TEMP)
220                         attr_name = "max";
221                 else if (type == FAN)
222                         attr_name = "min";
223         }
224
225         return attr_name;
226 }
227
228 /*
229  * This function translates the DT node name into the 'hwmon' attribute name.
230  * IBMPOWERNV device node appear like cooling-fan#2-data, amb-temp#1-thrs etc.
231  * which need to be mapped as fan2_input, temp1_max respectively before
232  * populating them inside hwmon device class.
233  */
234 static const char *parse_opal_node_name(const char *node_name,
235                                         enum sensors type, u32 *index)
236 {
237         char attr_suffix[MAX_ATTR_LEN];
238         const char *attr_name;
239         int err;
240
241         err = get_sensor_index_attr(node_name, index, attr_suffix);
242         if (err)
243                 return ERR_PTR(err);
244
245         attr_name = convert_opal_attr_name(type, attr_suffix);
246         if (!attr_name)
247                 return ERR_PTR(-ENOENT);
248
249         return attr_name;
250 }
251
252 static int get_sensor_type(struct device_node *np)
253 {
254         enum sensors type;
255         const char *str;
256
257         for (type = 0; type < ARRAY_SIZE(legacy_compatibles); type++) {
258                 if (of_device_is_compatible(np, legacy_compatibles[type]))
259                         return type;
260         }
261
262         /*
263          * Let's check if we have a newer device tree
264          */
265         if (!of_device_is_compatible(np, "ibm,opal-sensor"))
266                 return MAX_SENSOR_TYPE;
267
268         if (of_property_read_string(np, "sensor-type", &str))
269                 return MAX_SENSOR_TYPE;
270
271         for (type = 0; type < MAX_SENSOR_TYPE; type++)
272                 if (!strcmp(str, sensor_groups[type].name))
273                         return type;
274
275         return MAX_SENSOR_TYPE;
276 }
277
278 static u32 get_sensor_hwmon_index(struct sensor_data *sdata,
279                                   struct sensor_data *sdata_table, int count)
280 {
281         int i;
282
283         /*
284          * We don't use the OPAL index on newer device trees
285          */
286         if (sdata->opal_index != INVALID_INDEX) {
287                 for (i = 0; i < count; i++)
288                         if (sdata_table[i].opal_index == sdata->opal_index &&
289                             sdata_table[i].type == sdata->type)
290                                 return sdata_table[i].hwmon_index;
291         }
292         return ++sensor_groups[sdata->type].hwmon_index;
293 }
294
295 static int populate_attr_groups(struct platform_device *pdev)
296 {
297         struct platform_data *pdata = platform_get_drvdata(pdev);
298         const struct attribute_group **pgroups = pdata->attr_groups;
299         struct device_node *opal, *np;
300         enum sensors type;
301
302         opal = of_find_node_by_path("/ibm,opal/sensors");
303         for_each_child_of_node(opal, np) {
304                 const char *label;
305
306                 if (np->name == NULL)
307                         continue;
308
309                 type = get_sensor_type(np);
310                 if (type == MAX_SENSOR_TYPE)
311                         continue;
312
313                 sensor_groups[type].attr_count++;
314
315                 /*
316                  * add attributes for labels, min and max
317                  */
318                 if (!of_property_read_string(np, "label", &label))
319                         sensor_groups[type].attr_count++;
320                 if (of_find_property(np, "sensor-data-min", NULL))
321                         sensor_groups[type].attr_count++;
322                 if (of_find_property(np, "sensor-data-max", NULL))
323                         sensor_groups[type].attr_count++;
324         }
325
326         of_node_put(opal);
327
328         for (type = 0; type < MAX_SENSOR_TYPE; type++) {
329                 sensor_groups[type].group.attrs = devm_kcalloc(&pdev->dev,
330                                         sensor_groups[type].attr_count + 1,
331                                         sizeof(struct attribute *),
332                                         GFP_KERNEL);
333                 if (!sensor_groups[type].group.attrs)
334                         return -ENOMEM;
335
336                 pgroups[type] = &sensor_groups[type].group;
337                 pdata->sensors_count += sensor_groups[type].attr_count;
338                 sensor_groups[type].attr_count = 0;
339         }
340
341         return 0;
342 }
343
344 static void create_hwmon_attr(struct sensor_data *sdata, const char *attr_name,
345                               ssize_t (*show)(struct device *dev,
346                                               struct device_attribute *attr,
347                                               char *buf))
348 {
349         snprintf(sdata->name, MAX_ATTR_LEN, "%s%d_%s",
350                  sensor_groups[sdata->type].name, sdata->hwmon_index,
351                  attr_name);
352
353         sysfs_attr_init(&sdata->dev_attr.attr);
354         sdata->dev_attr.attr.name = sdata->name;
355         sdata->dev_attr.attr.mode = S_IRUGO;
356         sdata->dev_attr.show = show;
357 }
358
359 static void populate_sensor(struct sensor_data *sdata, int od, int hd, int sid,
360                             const char *attr_name, enum sensors type,
361                             const struct attribute_group *pgroup,
362                             ssize_t (*show)(struct device *dev,
363                                             struct device_attribute *attr,
364                                             char *buf))
365 {
366         sdata->id = sid;
367         sdata->type = type;
368         sdata->opal_index = od;
369         sdata->hwmon_index = hd;
370         create_hwmon_attr(sdata, attr_name, show);
371         pgroup->attrs[sensor_groups[type].attr_count++] = &sdata->dev_attr.attr;
372 }
373
374 static char *get_max_attr(enum sensors type)
375 {
376         switch (type) {
377         case POWER_INPUT:
378                 return "input_highest";
379         default:
380                 return "highest";
381         }
382 }
383
384 static char *get_min_attr(enum sensors type)
385 {
386         switch (type) {
387         case POWER_INPUT:
388                 return "input_lowest";
389         default:
390                 return "lowest";
391         }
392 }
393
394 /*
395  * Iterate through the device tree for each child of 'sensors' node, create
396  * a sysfs attribute file, the file is named by translating the DT node name
397  * to the name required by the higher 'hwmon' driver like fan1_input, temp1_max
398  * etc..
399  */
400 static int create_device_attrs(struct platform_device *pdev)
401 {
402         struct platform_data *pdata = platform_get_drvdata(pdev);
403         const struct attribute_group **pgroups = pdata->attr_groups;
404         struct device_node *opal, *np;
405         struct sensor_data *sdata;
406         u32 sensor_id;
407         enum sensors type;
408         u32 count = 0;
409         int err = 0;
410
411         opal = of_find_node_by_path("/ibm,opal/sensors");
412         sdata = devm_kcalloc(&pdev->dev,
413                              pdata->sensors_count, sizeof(*sdata),
414                              GFP_KERNEL);
415         if (!sdata) {
416                 err = -ENOMEM;
417                 goto exit_put_node;
418         }
419
420         for_each_child_of_node(opal, np) {
421                 const char *attr_name;
422                 u32 opal_index;
423                 const char *label;
424
425                 if (np->name == NULL)
426                         continue;
427
428                 type = get_sensor_type(np);
429                 if (type == MAX_SENSOR_TYPE)
430                         continue;
431
432                 /*
433                  * Newer device trees use a "sensor-data" property
434                  * name for input.
435                  */
436                 if (of_property_read_u32(np, "sensor-id", &sensor_id) &&
437                     of_property_read_u32(np, "sensor-data", &sensor_id)) {
438                         dev_info(&pdev->dev,
439                                  "'sensor-id' missing in the node '%s'\n",
440                                  np->name);
441                         continue;
442                 }
443
444                 sdata[count].id = sensor_id;
445                 sdata[count].type = type;
446
447                 /*
448                  * If we can not parse the node name, it means we are
449                  * running on a newer device tree. We can just forget
450                  * about the OPAL index and use a defaut value for the
451                  * hwmon attribute name
452                  */
453                 attr_name = parse_opal_node_name(np->name, type, &opal_index);
454                 if (IS_ERR(attr_name)) {
455                         attr_name = "input";
456                         opal_index = INVALID_INDEX;
457                 }
458
459                 sdata[count].opal_index = opal_index;
460                 sdata[count].hwmon_index =
461                         get_sensor_hwmon_index(&sdata[count], sdata, count);
462
463                 create_hwmon_attr(&sdata[count], attr_name, show_sensor);
464
465                 pgroups[type]->attrs[sensor_groups[type].attr_count++] =
466                                 &sdata[count++].dev_attr.attr;
467
468                 if (!of_property_read_string(np, "label", &label)) {
469                         /*
470                          * For the label attribute, we can reuse the
471                          * "properties" of the previous "input"
472                          * attribute. They are related to the same
473                          * sensor.
474                          */
475
476                         make_sensor_label(np, &sdata[count], label);
477                         populate_sensor(&sdata[count], opal_index,
478                                         sdata[count - 1].hwmon_index,
479                                         sensor_id, "label", type, pgroups[type],
480                                         show_label);
481                         count++;
482                 }
483
484                 if (!of_property_read_u32(np, "sensor-data-max", &sensor_id)) {
485                         attr_name = get_max_attr(type);
486                         populate_sensor(&sdata[count], opal_index,
487                                         sdata[count - 1].hwmon_index,
488                                         sensor_id, attr_name, type,
489                                         pgroups[type], show_sensor);
490                         count++;
491                 }
492
493                 if (!of_property_read_u32(np, "sensor-data-min", &sensor_id)) {
494                         attr_name = get_min_attr(type);
495                         populate_sensor(&sdata[count], opal_index,
496                                         sdata[count - 1].hwmon_index,
497                                         sensor_id, attr_name, type,
498                                         pgroups[type], show_sensor);
499                         count++;
500                 }
501         }
502
503 exit_put_node:
504         of_node_put(opal);
505         return err;
506 }
507
508 static int ibmpowernv_probe(struct platform_device *pdev)
509 {
510         struct platform_data *pdata;
511         struct device *hwmon_dev;
512         int err;
513
514         pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
515         if (!pdata)
516                 return -ENOMEM;
517
518         platform_set_drvdata(pdev, pdata);
519         pdata->sensors_count = 0;
520         err = populate_attr_groups(pdev);
521         if (err)
522                 return err;
523
524         /* Create sysfs attribute data for each sensor found in the DT */
525         err = create_device_attrs(pdev);
526         if (err)
527                 return err;
528
529         /* Finally, register with hwmon */
530         hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, DRVNAME,
531                                                            pdata,
532                                                            pdata->attr_groups);
533
534         return PTR_ERR_OR_ZERO(hwmon_dev);
535 }
536
537 static const struct platform_device_id opal_sensor_driver_ids[] = {
538         {
539                 .name = "opal-sensor",
540         },
541         { }
542 };
543 MODULE_DEVICE_TABLE(platform, opal_sensor_driver_ids);
544
545 static const struct of_device_id opal_sensor_match[] = {
546         { .compatible   = "ibm,opal-sensor" },
547         { },
548 };
549 MODULE_DEVICE_TABLE(of, opal_sensor_match);
550
551 static struct platform_driver ibmpowernv_driver = {
552         .probe          = ibmpowernv_probe,
553         .id_table       = opal_sensor_driver_ids,
554         .driver         = {
555                 .name   = DRVNAME,
556                 .of_match_table = opal_sensor_match,
557         },
558 };
559
560 module_platform_driver(ibmpowernv_driver);
561
562 MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>");
563 MODULE_DESCRIPTION("IBM POWERNV platform sensors");
564 MODULE_LICENSE("GPL");