Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+295
+23
Documentation/devicetree/bindings/hwmon/vexpress.txt
··· 1 + Versatile Express hwmon sensors 2 + ------------------------------- 3 + 4 + Requires node properties: 5 + - "compatible" value : one of 6 + "arm,vexpress-volt" 7 + "arm,vexpress-amp" 8 + "arm,vexpress-temp" 9 + "arm,vexpress-power" 10 + "arm,vexpress-energy" 11 + - "arm,vexpress-sysreg,func" when controlled via vexpress-sysreg 12 + (see Documentation/devicetree/bindings/arm/vexpress-sysreg.txt 13 + for more details) 14 + 15 + Optional node properties: 16 + - label : string describing the monitored value 17 + 18 + Example: 19 + energy@0 { 20 + compatible = "arm,vexpress-energy"; 21 + arm,vexpress-sysreg,func = <13 0>; 22 + label = "A15 Jcore"; 23 + };
+34
Documentation/hwmon/vexpress
··· 1 + Kernel driver vexpress 2 + ====================== 3 + 4 + Supported systems: 5 + * ARM Ltd. Versatile Express platform 6 + Prefix: 'vexpress' 7 + Datasheets: 8 + * "Hardware Description" sections of the Technical Reference Manuals 9 + for the Versatile Express boards: 10 + http://infocenter.arm.com/help/topic/com.arm.doc.subset.boards.express/index.html 11 + * Section "4.4.14. System Configuration registers" of the V2M-P1 TRM: 12 + http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0447-/index.html 13 + 14 + Author: Pawel Moll 15 + 16 + Description 17 + ----------- 18 + 19 + Versatile Express platform (http://www.arm.com/versatileexpress/) is a 20 + reference & prototyping system for ARM Ltd. processors. It can be set up 21 + from a wide range of boards, each of them containing (apart of the main 22 + chip/FPGA) a number of microcontrollers responsible for platform 23 + configuration and control. Theses microcontrollers can also monitor the 24 + board and its environment by a number of internal and external sensors, 25 + providing information about power lines voltages and currents, board 26 + temperature and power usage. Some of them also calculate consumed energy 27 + and provide a cumulative use counter. 28 + 29 + The configuration devices are _not_ memory mapped and must be accessed 30 + via a custom interface, abstracted by the "vexpress_config" API. 31 + 32 + As these devices are non-discoverable, they must be described in a Device 33 + Tree passed to the kernel. Details of the DT binding for them can be found 34 + in Documentation/devicetree/bindings/hwmon/vexpress.txt.
+8
drivers/hwmon/Kconfig
··· 1197 1197 This driver can also be built as a module. If so it will be called 1198 1198 twl4030-madc-hwmon. 1199 1199 1200 + config 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 + 1200 1208 config SENSORS_VIA_CPUTEMP 1201 1209 tristate "VIA CPU temperature sensor" 1202 1210 depends on X86
+1
drivers/hwmon/Makefile
··· 121 121 obj-$(CONFIG_SENSORS_TMP401) += tmp401.o 122 122 obj-$(CONFIG_SENSORS_TMP421) += tmp421.o 123 123 obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o 124 + obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress.o 124 125 obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o 125 126 obj-$(CONFIG_SENSORS_VIA686A) += via686a.o 126 127 obj-$(CONFIG_SENSORS_VT1211) += vt1211.o
+229
drivers/hwmon/vexpress.c
··· 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 + 26 + struct vexpress_hwmon_data { 27 + struct device *hwmon_dev; 28 + struct vexpress_config_func *func; 29 + }; 30 + 31 + static 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 + 40 + static 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 + 51 + static 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 + 66 + static 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 + 86 + static DEVICE_ATTR(name, S_IRUGO, vexpress_hwmon_name_show, NULL); 87 + 88 + #define VEXPRESS_HWMON_ATTRS(_name, _label_attr, _input_attr) \ 89 + struct 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) 97 + static DEVICE_ATTR(in1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); 98 + static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, vexpress_hwmon_u32_show, 99 + NULL, 1000); 100 + static VEXPRESS_HWMON_ATTRS(volt, in1_label, in1_input); 101 + static struct attribute_group vexpress_hwmon_group_volt = { 102 + .attrs = vexpress_hwmon_attrs_volt, 103 + }; 104 + #endif 105 + 106 + static DEVICE_ATTR(curr1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); 107 + static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, vexpress_hwmon_u32_show, 108 + NULL, 1000); 109 + static VEXPRESS_HWMON_ATTRS(amp, curr1_label, curr1_input); 110 + static struct attribute_group vexpress_hwmon_group_amp = { 111 + .attrs = vexpress_hwmon_attrs_amp, 112 + }; 113 + 114 + static DEVICE_ATTR(temp1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); 115 + static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, vexpress_hwmon_u32_show, 116 + NULL, 1000); 117 + static VEXPRESS_HWMON_ATTRS(temp, temp1_label, temp1_input); 118 + static struct attribute_group vexpress_hwmon_group_temp = { 119 + .attrs = vexpress_hwmon_attrs_temp, 120 + }; 121 + 122 + static DEVICE_ATTR(power1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); 123 + static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, vexpress_hwmon_u32_show, 124 + NULL, 1); 125 + static VEXPRESS_HWMON_ATTRS(power, power1_label, power1_input); 126 + static struct attribute_group vexpress_hwmon_group_power = { 127 + .attrs = vexpress_hwmon_attrs_power, 128 + }; 129 + 130 + static DEVICE_ATTR(energy1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); 131 + static SENSOR_DEVICE_ATTR(energy1_input, S_IRUGO, vexpress_hwmon_u64_show, 132 + NULL, 1); 133 + static VEXPRESS_HWMON_ATTRS(energy, energy1_label, energy1_input); 134 + static struct attribute_group vexpress_hwmon_group_energy = { 135 + .attrs = vexpress_hwmon_attrs_energy, 136 + }; 137 + 138 + static 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 + }; 160 + MODULE_DEVICE_TABLE(of, vexpress_hwmon_of_match); 161 + 162 + static 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 + 193 + error: 194 + sysfs_remove_group(&pdev->dev.kobj, match->data); 195 + vexpress_config_func_put(data->func); 196 + return err; 197 + } 198 + 199 + static 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 + 214 + static 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 + 224 + module_platform_driver(vexpress_hwmon_driver); 225 + 226 + MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>"); 227 + MODULE_DESCRIPTION("Versatile Express hwmon sensors driver"); 228 + MODULE_LICENSE("GPL"); 229 + MODULE_ALIAS("platform:vexpress-hwmon");