linux/drivers/hwmon/vexpress-hwmon.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 regmap *reg;
  30};
  31
  32static ssize_t vexpress_hwmon_label_show(struct device *dev,
  33                struct device_attribute *dev_attr, char *buffer)
  34{
  35        const char *label = of_get_property(dev->of_node, "label", NULL);
  36
  37        return snprintf(buffer, PAGE_SIZE, "%s\n", label);
  38}
  39
  40static ssize_t vexpress_hwmon_u32_show(struct device *dev,
  41                struct device_attribute *dev_attr, char *buffer)
  42{
  43        struct vexpress_hwmon_data *data = dev_get_drvdata(dev);
  44        int err;
  45        u32 value;
  46
  47        err = regmap_read(data->reg, 0, &value);
  48        if (err)
  49                return err;
  50
  51        return snprintf(buffer, PAGE_SIZE, "%u\n", value /
  52                        to_sensor_dev_attr(dev_attr)->index);
  53}
  54
  55static ssize_t vexpress_hwmon_u64_show(struct device *dev,
  56                struct device_attribute *dev_attr, char *buffer)
  57{
  58        struct vexpress_hwmon_data *data = dev_get_drvdata(dev);
  59        int err;
  60        u32 value_hi, value_lo;
  61
  62        err = regmap_read(data->reg, 0, &value_lo);
  63        if (err)
  64                return err;
  65
  66        err = regmap_read(data->reg, 1, &value_hi);
  67        if (err)
  68                return err;
  69
  70        return snprintf(buffer, PAGE_SIZE, "%llu\n",
  71                        div_u64(((u64)value_hi << 32) | value_lo,
  72                        to_sensor_dev_attr(dev_attr)->index));
  73}
  74
  75static umode_t vexpress_hwmon_attr_is_visible(struct kobject *kobj,
  76                struct attribute *attr, int index)
  77{
  78        struct device *dev = kobj_to_dev(kobj);
  79        struct device_attribute *dev_attr = container_of(attr,
  80                                struct device_attribute, attr);
  81
  82        if (dev_attr->show == vexpress_hwmon_label_show &&
  83                        !of_get_property(dev->of_node, "label", NULL))
  84                return 0;
  85
  86        return attr->mode;
  87}
  88
  89struct vexpress_hwmon_type {
  90        const char *name;
  91        const struct attribute_group **attr_groups;
  92};
  93
  94#if !defined(CONFIG_REGULATOR_VEXPRESS)
  95static DEVICE_ATTR(in1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
  96static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, vexpress_hwmon_u32_show,
  97                NULL, 1000);
  98static struct attribute *vexpress_hwmon_attrs_volt[] = {
  99        &dev_attr_in1_label.attr,
 100        &sensor_dev_attr_in1_input.dev_attr.attr,
 101        NULL
 102};
 103static struct attribute_group vexpress_hwmon_group_volt = {
 104        .is_visible = vexpress_hwmon_attr_is_visible,
 105        .attrs = vexpress_hwmon_attrs_volt,
 106};
 107static struct vexpress_hwmon_type vexpress_hwmon_volt = {
 108        .name = "vexpress_volt",
 109        .attr_groups = (const struct attribute_group *[]) {
 110                &vexpress_hwmon_group_volt,
 111                NULL,
 112        },
 113};
 114#endif
 115
 116static DEVICE_ATTR(curr1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
 117static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, vexpress_hwmon_u32_show,
 118                NULL, 1000);
 119static struct attribute *vexpress_hwmon_attrs_amp[] = {
 120        &dev_attr_curr1_label.attr,
 121        &sensor_dev_attr_curr1_input.dev_attr.attr,
 122        NULL
 123};
 124static struct attribute_group vexpress_hwmon_group_amp = {
 125        .is_visible = vexpress_hwmon_attr_is_visible,
 126        .attrs = vexpress_hwmon_attrs_amp,
 127};
 128static struct vexpress_hwmon_type vexpress_hwmon_amp = {
 129        .name = "vexpress_amp",
 130        .attr_groups = (const struct attribute_group *[]) {
 131                &vexpress_hwmon_group_amp,
 132                NULL
 133        },
 134};
 135
 136static DEVICE_ATTR(temp1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
 137static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, vexpress_hwmon_u32_show,
 138                NULL, 1000);
 139static struct attribute *vexpress_hwmon_attrs_temp[] = {
 140        &dev_attr_temp1_label.attr,
 141        &sensor_dev_attr_temp1_input.dev_attr.attr,
 142        NULL
 143};
 144static struct attribute_group vexpress_hwmon_group_temp = {
 145        .is_visible = vexpress_hwmon_attr_is_visible,
 146        .attrs = vexpress_hwmon_attrs_temp,
 147};
 148static struct vexpress_hwmon_type vexpress_hwmon_temp = {
 149        .name = "vexpress_temp",
 150        .attr_groups = (const struct attribute_group *[]) {
 151                &vexpress_hwmon_group_temp,
 152                NULL
 153        },
 154};
 155
 156static DEVICE_ATTR(power1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
 157static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, vexpress_hwmon_u32_show,
 158                NULL, 1);
 159static struct attribute *vexpress_hwmon_attrs_power[] = {
 160        &dev_attr_power1_label.attr,
 161        &sensor_dev_attr_power1_input.dev_attr.attr,
 162        NULL
 163};
 164static struct attribute_group vexpress_hwmon_group_power = {
 165        .is_visible = vexpress_hwmon_attr_is_visible,
 166        .attrs = vexpress_hwmon_attrs_power,
 167};
 168static struct vexpress_hwmon_type vexpress_hwmon_power = {
 169        .name = "vexpress_power",
 170        .attr_groups = (const struct attribute_group *[]) {
 171                &vexpress_hwmon_group_power,
 172                NULL
 173        },
 174};
 175
 176static DEVICE_ATTR(energy1_label, S_IRUGO, vexpress_hwmon_label_show, NULL);
 177static SENSOR_DEVICE_ATTR(energy1_input, S_IRUGO, vexpress_hwmon_u64_show,
 178                NULL, 1);
 179static struct attribute *vexpress_hwmon_attrs_energy[] = {
 180        &dev_attr_energy1_label.attr,
 181        &sensor_dev_attr_energy1_input.dev_attr.attr,
 182        NULL
 183};
 184static struct attribute_group vexpress_hwmon_group_energy = {
 185        .is_visible = vexpress_hwmon_attr_is_visible,
 186        .attrs = vexpress_hwmon_attrs_energy,
 187};
 188static struct vexpress_hwmon_type vexpress_hwmon_energy = {
 189        .name = "vexpress_energy",
 190        .attr_groups = (const struct attribute_group *[]) {
 191                &vexpress_hwmon_group_energy,
 192                NULL
 193        },
 194};
 195
 196static const struct of_device_id vexpress_hwmon_of_match[] = {
 197#if !defined(CONFIG_REGULATOR_VEXPRESS)
 198        {
 199                .compatible = "arm,vexpress-volt",
 200                .data = &vexpress_hwmon_volt,
 201        },
 202#endif
 203        {
 204                .compatible = "arm,vexpress-amp",
 205                .data = &vexpress_hwmon_amp,
 206        }, {
 207                .compatible = "arm,vexpress-temp",
 208                .data = &vexpress_hwmon_temp,
 209        }, {
 210                .compatible = "arm,vexpress-power",
 211                .data = &vexpress_hwmon_power,
 212        }, {
 213                .compatible = "arm,vexpress-energy",
 214                .data = &vexpress_hwmon_energy,
 215        },
 216        {}
 217};
 218MODULE_DEVICE_TABLE(of, vexpress_hwmon_of_match);
 219
 220static int vexpress_hwmon_probe(struct platform_device *pdev)
 221{
 222        const struct of_device_id *match;
 223        struct vexpress_hwmon_data *data;
 224        const struct vexpress_hwmon_type *type;
 225
 226        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
 227        if (!data)
 228                return -ENOMEM;
 229        platform_set_drvdata(pdev, data);
 230
 231        match = of_match_device(vexpress_hwmon_of_match, &pdev->dev);
 232        if (!match)
 233                return -ENODEV;
 234        type = match->data;
 235
 236        data->reg = devm_regmap_init_vexpress_config(&pdev->dev);
 237        if (IS_ERR(data->reg))
 238                return PTR_ERR(data->reg);
 239
 240        data->hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,
 241                        type->name, data, type->attr_groups);
 242
 243        return PTR_ERR_OR_ZERO(data->hwmon_dev);
 244}
 245
 246static struct platform_driver vexpress_hwmon_driver = {
 247        .probe = vexpress_hwmon_probe,
 248        .driver = {
 249                .name = DRVNAME,
 250                .of_match_table = vexpress_hwmon_of_match,
 251        },
 252};
 253
 254module_platform_driver(vexpress_hwmon_driver);
 255
 256MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>");
 257MODULE_DESCRIPTION("Versatile Express hwmon sensors driver");
 258MODULE_LICENSE("GPL");
 259MODULE_ALIAS("platform:vexpress-hwmon");
 260