linux/drivers/hwmon/vexpress.c
<<
>>
Prefs
   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.h>
  23#include <linux/of_device.h>
  24#include <linux/platform_device.h>
  25#include <linux/vexpress.h>
  26
  27struct vexpress_hwmon_data {
  28        struct device *hwmon_dev;
  29        struct vexpress_config_func *func;
  30};
  31
  32static ssize_t vexpress_hwmon_name_show(struct device *dev,
  33                struct device_attribute *dev_attr, char *buffer)
  34{
  35        const char *compatible = of_get_property(dev->of_node, "compatible",
  36                        NULL);
  37
  38        return sprintf(buffer, "%s\n", compatible);
  39}
  40
  41static ssize_t vexpress_hwmon_label_show(struct device *dev,
  42                struct device_attribute *dev_attr, char *buffer)
  43{
  44        const char *label = of_get_property(dev->of_node, "label", NULL);
  45
  46        if (!label)
  47                return -ENOENT;
  48
  49        return snprintf(buffer, PAGE_SIZE, "%s\n", label);
  50}
  51
  52static ssize_t vexpress_hwmon_u32_show(struct device *dev,
  53                struct device_attribute *dev_attr, char *buffer)
  54{
  55        struct vexpress_hwmon_data *data = dev_get_drvdata(dev);
  56        int err;
  57        u32 value;
  58
  59        err = vexpress_config_read(data->func, 0, &value);
  60        if (err)
  61                return err;
  62
  63        return snprintf(buffer, PAGE_SIZE, "%u\n", value /
  64                        to_sensor_dev_attr(dev_attr)->index);
  65}
  66
  67static ssize_t vexpress_hwmon_u64_show(struct device *dev,
  68                struct device_attribute *dev_attr, char *buffer)
  69{
  70        struct vexpress_hwmon_data *data = dev_get_drvdata(dev);
  71        int err;
  72        u32 value_hi, value_lo;
  73
  74        err = vexpress_config_read(data->func, 0, &value_lo);
  75        if (err)
  76                return err;
  77
  78        err = vexpress_config_read(data->func, 1, &value_hi);
  79        if (err)
  80                return err;
  81
  82        return snprintf(buffer, PAGE_SIZE, "%llu\n",
  83                        div_u64(((u64)value_hi << 32) | value_lo,
  84                        to_sensor_dev_attr(dev_attr)->index));
  85}
  86
  87static DEVICE_ATTR(name, S_IRUGO, vexpress_hwmon_name_show, NULL);
  88
  89#define VEXPRESS_HWMON_ATTRS(_name, _label_attr, _input_attr)   \
  90struct attribute *vexpress_hwmon_attrs_##_name[] = {            \
  91        &dev_attr_name.attr,                                    \
  92        &dev_attr_##_label_attr.attr,                           \
  93        &sensor_dev_attr_##_input_attr.dev_attr.attr,           \
  94        NULL                                                    \
  95}
  96
  97#if !defined(CONFIG_REGULATOR_VEXPRESS)
  98static DEVICE_ATTR(in1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
  99static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, vexpress_hwmon_u32_show,
 100                NULL, 1000);
 101static VEXPRESS_HWMON_ATTRS(volt, in1_label, in1_input);
 102static struct attribute_group vexpress_hwmon_group_volt = {
 103        .attrs = vexpress_hwmon_attrs_volt,
 104};
 105#endif
 106
 107static DEVICE_ATTR(curr1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
 108static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, vexpress_hwmon_u32_show,
 109                NULL, 1000);
 110static VEXPRESS_HWMON_ATTRS(amp, curr1_label, curr1_input);
 111static struct attribute_group vexpress_hwmon_group_amp = {
 112        .attrs = vexpress_hwmon_attrs_amp,
 113};
 114
 115static DEVICE_ATTR(temp1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
 116static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, vexpress_hwmon_u32_show,
 117                NULL, 1000);
 118static VEXPRESS_HWMON_ATTRS(temp, temp1_label, temp1_input);
 119static struct attribute_group vexpress_hwmon_group_temp = {
 120        .attrs = vexpress_hwmon_attrs_temp,
 121};
 122
 123static DEVICE_ATTR(power1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
 124static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, vexpress_hwmon_u32_show,
 125                NULL, 1);
 126static VEXPRESS_HWMON_ATTRS(power, power1_label, power1_input);
 127static struct attribute_group vexpress_hwmon_group_power = {
 128        .attrs = vexpress_hwmon_attrs_power,
 129};
 130
 131static DEVICE_ATTR(energy1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
 132static SENSOR_DEVICE_ATTR(energy1_input, S_IRUGO, vexpress_hwmon_u64_show,
 133                NULL, 1);
 134static VEXPRESS_HWMON_ATTRS(energy, energy1_label, energy1_input);
 135static struct attribute_group vexpress_hwmon_group_energy = {
 136        .attrs = vexpress_hwmon_attrs_energy,
 137};
 138
 139static struct of_device_id vexpress_hwmon_of_match[] = {
 140#if !defined(CONFIG_REGULATOR_VEXPRESS)
 141        {
 142                .compatible = "arm,vexpress-volt",
 143                .data = &vexpress_hwmon_group_volt,
 144        },
 145#endif
 146        {
 147                .compatible = "arm,vexpress-amp",
 148                .data = &vexpress_hwmon_group_amp,
 149        }, {
 150                .compatible = "arm,vexpress-temp",
 151                .data = &vexpress_hwmon_group_temp,
 152        }, {
 153                .compatible = "arm,vexpress-power",
 154                .data = &vexpress_hwmon_group_power,
 155        }, {
 156                .compatible = "arm,vexpress-energy",
 157                .data = &vexpress_hwmon_group_energy,
 158        },
 159        {}
 160};
 161MODULE_DEVICE_TABLE(of, vexpress_hwmon_of_match);
 162
 163static int vexpress_hwmon_probe(struct platform_device *pdev)
 164{
 165        int err;
 166        const struct of_device_id *match;
 167        struct vexpress_hwmon_data *data;
 168
 169        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
 170        if (!data)
 171                return -ENOMEM;
 172        platform_set_drvdata(pdev, data);
 173
 174        match = of_match_device(vexpress_hwmon_of_match, &pdev->dev);
 175        if (!match)
 176                return -ENODEV;
 177
 178        data->func = vexpress_config_func_get_by_dev(&pdev->dev);
 179        if (!data->func)
 180                return -ENODEV;
 181
 182        err = sysfs_create_group(&pdev->dev.kobj, match->data);
 183        if (err)
 184                goto error;
 185
 186        data->hwmon_dev = hwmon_device_register(&pdev->dev);
 187        if (IS_ERR(data->hwmon_dev)) {
 188                err = PTR_ERR(data->hwmon_dev);
 189                goto error;
 190        }
 191
 192        return 0;
 193
 194error:
 195        sysfs_remove_group(&pdev->dev.kobj, match->data);
 196        vexpress_config_func_put(data->func);
 197        return err;
 198}
 199
 200static int vexpress_hwmon_remove(struct platform_device *pdev)
 201{
 202        struct vexpress_hwmon_data *data = platform_get_drvdata(pdev);
 203        const struct of_device_id *match;
 204
 205        hwmon_device_unregister(data->hwmon_dev);
 206
 207        match = of_match_device(vexpress_hwmon_of_match, &pdev->dev);
 208        sysfs_remove_group(&pdev->dev.kobj, match->data);
 209
 210        vexpress_config_func_put(data->func);
 211
 212        return 0;
 213}
 214
 215static struct platform_driver vexpress_hwmon_driver = {
 216        .probe = vexpress_hwmon_probe,
 217        .remove = vexpress_hwmon_remove,
 218        .driver = {
 219                .name = DRVNAME,
 220                .owner = THIS_MODULE,
 221                .of_match_table = vexpress_hwmon_of_match,
 222        },
 223};
 224
 225module_platform_driver(vexpress_hwmon_driver);
 226
 227MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>");
 228MODULE_DESCRIPTION("Versatile Express hwmon sensors driver");
 229MODULE_LICENSE("GPL");
 230MODULE_ALIAS("platform:vexpress-hwmon");
 231