aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorPawel Moll <pawel.moll@arm.com>2012-09-17 13:40:09 -0400
committerPawel Moll <pawel.moll@arm.com>2012-10-16 12:12:35 -0400
commit48ed8877244637b52aec0a114cdccd8ec26e66b1 (patch)
tree56e04096ead15bd84d1b768f2630a36c9c832a70 /drivers/hwmon
parentddffeb8c4d0331609ef2581d84de4d763607bd37 (diff)
hwmon: Versatile Express hwmon driver
hwmon framework driver for Versatile Express sensors, providing information about board level voltage (only when regulator driver is not configured), currents, temperature and power/energy usage. Labels for the values can be defined as DT properties. Signed-off-by: Pawel Moll <pawel.moll@arm.com> Acked-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/Kconfig8
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/vexpress.c229
3 files changed, 238 insertions, 0 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index c4633de64465..db213fe958a5 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1197,6 +1197,14 @@ config SENSORS_TWL4030_MADC
1197 This driver can also be built as a module. If so it will be called 1197 This driver can also be built as a module. If so it will be called
1198 twl4030-madc-hwmon. 1198 twl4030-madc-hwmon.
1199 1199
1200config SENSORS_VEXPRESS
1201 tristate "Versatile Express"
1202 depends on VEXPRESS_CONFIG
1203 help
1204 This driver provides support for hardware sensors available on
1205 the ARM Ltd's Versatile Express platform. It can provide wide
1206 range of information like temperature, power, energy.
1207
1200config SENSORS_VIA_CPUTEMP 1208config SENSORS_VIA_CPUTEMP
1201 tristate "VIA CPU temperature sensor" 1209 tristate "VIA CPU temperature sensor"
1202 depends on X86 1210 depends on X86
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 8d5fcb5e8e9f..aac8b7c619d6 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -121,6 +121,7 @@ obj-$(CONFIG_SENSORS_TMP102) += tmp102.o
121obj-$(CONFIG_SENSORS_TMP401) += tmp401.o 121obj-$(CONFIG_SENSORS_TMP401) += tmp401.o
122obj-$(CONFIG_SENSORS_TMP421) += tmp421.o 122obj-$(CONFIG_SENSORS_TMP421) += tmp421.o
123obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o 123obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o
124obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress.o
124obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o 125obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
125obj-$(CONFIG_SENSORS_VIA686A) += via686a.o 126obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
126obj-$(CONFIG_SENSORS_VT1211) += vt1211.o 127obj-$(CONFIG_SENSORS_VT1211) += vt1211.o
diff --git a/drivers/hwmon/vexpress.c b/drivers/hwmon/vexpress.c
new file mode 100644
index 000000000000..59fd1268e58a
--- /dev/null
+++ b/drivers/hwmon/vexpress.c
@@ -0,0 +1,229 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License version 2 as
4 * published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * Copyright (C) 2012 ARM Limited
12 */
13
14#define DRVNAME "vexpress-hwmon"
15#define pr_fmt(fmt) DRVNAME ": " fmt
16
17#include <linux/device.h>
18#include <linux/err.h>
19#include <linux/hwmon.h>
20#include <linux/hwmon-sysfs.h>
21#include <linux/module.h>
22#include <linux/of_device.h>
23#include <linux/platform_device.h>
24#include <linux/vexpress.h>
25
26struct vexpress_hwmon_data {
27 struct device *hwmon_dev;
28 struct vexpress_config_func *func;
29};
30
31static ssize_t vexpress_hwmon_name_show(struct device *dev,
32 struct device_attribute *dev_attr, char *buffer)
33{
34 const char *compatible = of_get_property(dev->of_node, "compatible",
35 NULL);
36
37 return sprintf(buffer, "%s\n", compatible);
38}
39
40static ssize_t vexpress_hwmon_label_show(struct device *dev,
41 struct device_attribute *dev_attr, char *buffer)
42{
43 const char *label = of_get_property(dev->of_node, "label", NULL);
44
45 if (!label)
46 return -ENOENT;
47
48 return snprintf(buffer, PAGE_SIZE, "%s\n", label);
49}
50
51static ssize_t vexpress_hwmon_u32_show(struct device *dev,
52 struct device_attribute *dev_attr, char *buffer)
53{
54 struct vexpress_hwmon_data *data = dev_get_drvdata(dev);
55 int err;
56 u32 value;
57
58 err = vexpress_config_read(data->func, 0, &value);
59 if (err)
60 return err;
61
62 return snprintf(buffer, PAGE_SIZE, "%u\n", value /
63 to_sensor_dev_attr(dev_attr)->index);
64}
65
66static ssize_t vexpress_hwmon_u64_show(struct device *dev,
67 struct device_attribute *dev_attr, char *buffer)
68{
69 struct vexpress_hwmon_data *data = dev_get_drvdata(dev);
70 int err;
71 u32 value_hi, value_lo;
72
73 err = vexpress_config_read(data->func, 0, &value_lo);
74 if (err)
75 return err;
76
77 err = vexpress_config_read(data->func, 1, &value_hi);
78 if (err)
79 return err;
80
81 return snprintf(buffer, PAGE_SIZE, "%llu\n",
82 div_u64(((u64)value_hi << 32) | value_lo,
83 to_sensor_dev_attr(dev_attr)->index));
84}
85
86static DEVICE_ATTR(name, S_IRUGO, vexpress_hwmon_name_show, NULL);
87
88#define VEXPRESS_HWMON_ATTRS(_name, _label_attr, _input_attr) \
89struct attribute *vexpress_hwmon_attrs_##_name[] = { \
90 &dev_attr_name.attr, \
91 &dev_attr_##_label_attr.attr, \
92 &sensor_dev_attr_##_input_attr.dev_attr.attr, \
93 NULL \
94}
95
96#if !defined(CONFIG_REGULATOR_VEXPRESS)
97static DEVICE_ATTR(in1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
98static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, vexpress_hwmon_u32_show,
99 NULL, 1000);
100static VEXPRESS_HWMON_ATTRS(volt, in1_label, in1_input);
101static struct attribute_group vexpress_hwmon_group_volt = {
102 .attrs = vexpress_hwmon_attrs_volt,
103};
104#endif
105
106static DEVICE_ATTR(curr1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
107static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, vexpress_hwmon_u32_show,
108 NULL, 1000);
109static VEXPRESS_HWMON_ATTRS(amp, curr1_label, curr1_input);
110static struct attribute_group vexpress_hwmon_group_amp = {
111 .attrs = vexpress_hwmon_attrs_amp,
112};
113
114static DEVICE_ATTR(temp1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
115static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, vexpress_hwmon_u32_show,
116 NULL, 1000);
117static VEXPRESS_HWMON_ATTRS(temp, temp1_label, temp1_input);
118static struct attribute_group vexpress_hwmon_group_temp = {
119 .attrs = vexpress_hwmon_attrs_temp,
120};
121
122static DEVICE_ATTR(power1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
123static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, vexpress_hwmon_u32_show,
124 NULL, 1);
125static VEXPRESS_HWMON_ATTRS(power, power1_label, power1_input);
126static struct attribute_group vexpress_hwmon_group_power = {
127 .attrs = vexpress_hwmon_attrs_power,
128};
129
130static DEVICE_ATTR(energy1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
131static SENSOR_DEVICE_ATTR(energy1_input, S_IRUGO, vexpress_hwmon_u64_show,
132 NULL, 1);
133static VEXPRESS_HWMON_ATTRS(energy, energy1_label, energy1_input);
134static struct attribute_group vexpress_hwmon_group_energy = {
135 .attrs = vexpress_hwmon_attrs_energy,
136};
137
138static struct of_device_id vexpress_hwmon_of_match[] = {
139#if !defined(CONFIG_REGULATOR_VEXPRESS)
140 {
141 .compatible = "arm,vexpress-volt",
142 .data = &vexpress_hwmon_group_volt,
143 },
144#endif
145 {
146 .compatible = "arm,vexpress-amp",
147 .data = &vexpress_hwmon_group_amp,
148 }, {
149 .compatible = "arm,vexpress-temp",
150 .data = &vexpress_hwmon_group_temp,
151 }, {
152 .compatible = "arm,vexpress-power",
153 .data = &vexpress_hwmon_group_power,
154 }, {
155 .compatible = "arm,vexpress-energy",
156 .data = &vexpress_hwmon_group_energy,
157 },
158 {}
159};
160MODULE_DEVICE_TABLE(of, vexpress_hwmon_of_match);
161
162static int vexpress_hwmon_probe(struct platform_device *pdev)
163{
164 int err;
165 const struct of_device_id *match;
166 struct vexpress_hwmon_data *data;
167
168 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
169 if (!data)
170 return -ENOMEM;
171 platform_set_drvdata(pdev, data);
172
173 match = of_match_device(vexpress_hwmon_of_match, &pdev->dev);
174 if (!match)
175 return -ENODEV;
176
177 data->func = vexpress_config_func_get_by_dev(&pdev->dev);
178 if (!data->func)
179 return -ENODEV;
180
181 err = sysfs_create_group(&pdev->dev.kobj, match->data);
182 if (err)
183 goto error;
184
185 data->hwmon_dev = hwmon_device_register(&pdev->dev);
186 if (IS_ERR(data->hwmon_dev)) {
187 err = PTR_ERR(data->hwmon_dev);
188 goto error;
189 }
190
191 return 0;
192
193error:
194 sysfs_remove_group(&pdev->dev.kobj, match->data);
195 vexpress_config_func_put(data->func);
196 return err;
197}
198
199static int __devexit vexpress_hwmon_remove(struct platform_device *pdev)
200{
201 struct vexpress_hwmon_data *data = platform_get_drvdata(pdev);
202 const struct of_device_id *match;
203
204 hwmon_device_unregister(data->hwmon_dev);
205
206 match = of_match_device(vexpress_hwmon_of_match, &pdev->dev);
207 sysfs_remove_group(&pdev->dev.kobj, match->data);
208
209 vexpress_config_func_put(data->func);
210
211 return 0;
212}
213
214static struct platform_driver vexpress_hwmon_driver = {
215 .probe = vexpress_hwmon_probe,
216 .remove = __devexit_p(vexpress_hwmon_remove),
217 .driver = {
218 .name = DRVNAME,
219 .owner = THIS_MODULE,
220 .of_match_table = vexpress_hwmon_of_match,
221 },
222};
223
224module_platform_driver(vexpress_hwmon_driver);
225
226MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>");
227MODULE_DESCRIPTION("Versatile Express hwmon sensors driver");
228MODULE_LICENSE("GPL");
229MODULE_ALIAS("platform:vexpress-hwmon");