linux/drivers/hwmon/ad7314.c
<<
>>
Prefs
   1/*
   2 * AD7314 digital temperature sensor driver for AD7314, ADT7301 and ADT7302
   3 *
   4 * Copyright 2010 Analog Devices Inc.
   5 *
   6 * Licensed under the GPL-2 or later.
   7 *
   8 * Conversion to hwmon from IIO done by Jonathan Cameron <jic23@cam.ac.uk>
   9 */
  10#include <linux/device.h>
  11#include <linux/kernel.h>
  12#include <linux/slab.h>
  13#include <linux/sysfs.h>
  14#include <linux/spi/spi.h>
  15#include <linux/module.h>
  16#include <linux/err.h>
  17#include <linux/hwmon.h>
  18#include <linux/hwmon-sysfs.h>
  19#include <linux/bitops.h>
  20
  21/*
  22 * AD7314 temperature masks
  23 */
  24#define AD7314_TEMP_MASK                0x7FE0
  25#define AD7314_TEMP_SHIFT               5
  26
  27/*
  28 * ADT7301 and ADT7302 temperature masks
  29 */
  30#define ADT7301_TEMP_MASK               0x3FFF
  31
  32enum ad7314_variant {
  33        adt7301,
  34        adt7302,
  35        ad7314,
  36};
  37
  38struct ad7314_data {
  39        struct spi_device       *spi_dev;
  40        struct device           *hwmon_dev;
  41        u16 rx ____cacheline_aligned;
  42};
  43
  44static int ad7314_spi_read(struct ad7314_data *chip)
  45{
  46        int ret;
  47
  48        ret = spi_read(chip->spi_dev, (u8 *)&chip->rx, sizeof(chip->rx));
  49        if (ret < 0) {
  50                dev_err(&chip->spi_dev->dev, "SPI read error\n");
  51                return ret;
  52        }
  53
  54        return be16_to_cpu(chip->rx);
  55}
  56
  57static ssize_t ad7314_show_temperature(struct device *dev,
  58                struct device_attribute *attr,
  59                char *buf)
  60{
  61        struct ad7314_data *chip = dev_get_drvdata(dev);
  62        s16 data;
  63        int ret;
  64
  65        ret = ad7314_spi_read(chip);
  66        if (ret < 0)
  67                return ret;
  68        switch (spi_get_device_id(chip->spi_dev)->driver_data) {
  69        case ad7314:
  70                data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT;
  71                data = sign_extend32(data, 9);
  72
  73                return sprintf(buf, "%d\n", 250 * data);
  74        case adt7301:
  75        case adt7302:
  76                /*
  77                 * Documented as a 13 bit twos complement register
  78                 * with a sign bit - which is a 14 bit 2's complement
  79                 * register.  1lsb - 31.25 milli degrees centigrade
  80                 */
  81                data = ret & ADT7301_TEMP_MASK;
  82                data = sign_extend32(data, 13);
  83
  84                return sprintf(buf, "%d\n",
  85                               DIV_ROUND_CLOSEST(data * 3125, 100));
  86        default:
  87                return -EINVAL;
  88        }
  89}
  90
  91static ssize_t ad7314_show_name(struct device *dev,
  92                                struct device_attribute *devattr, char *buf)
  93{
  94        return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
  95}
  96
  97static DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL);
  98static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
  99                          ad7314_show_temperature, NULL, 0);
 100
 101static struct attribute *ad7314_attributes[] = {
 102        &dev_attr_name.attr,
 103        &sensor_dev_attr_temp1_input.dev_attr.attr,
 104        NULL,
 105};
 106
 107static const struct attribute_group ad7314_group = {
 108        .attrs = ad7314_attributes,
 109};
 110
 111static int ad7314_probe(struct spi_device *spi_dev)
 112{
 113        int ret;
 114        struct ad7314_data *chip;
 115
 116        chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL);
 117        if (chip == NULL)
 118                return -ENOMEM;
 119
 120        spi_set_drvdata(spi_dev, chip);
 121
 122        ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
 123        if (ret < 0)
 124                return ret;
 125
 126        chip->hwmon_dev = hwmon_device_register(&spi_dev->dev);
 127        if (IS_ERR(chip->hwmon_dev)) {
 128                ret = PTR_ERR(chip->hwmon_dev);
 129                goto error_remove_group;
 130        }
 131        chip->spi_dev = spi_dev;
 132
 133        return 0;
 134error_remove_group:
 135        sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
 136        return ret;
 137}
 138
 139static int ad7314_remove(struct spi_device *spi_dev)
 140{
 141        struct ad7314_data *chip = spi_get_drvdata(spi_dev);
 142
 143        hwmon_device_unregister(chip->hwmon_dev);
 144        sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
 145
 146        return 0;
 147}
 148
 149static const struct spi_device_id ad7314_id[] = {
 150        { "adt7301", adt7301 },
 151        { "adt7302", adt7302 },
 152        { "ad7314", ad7314 },
 153        { }
 154};
 155MODULE_DEVICE_TABLE(spi, ad7314_id);
 156
 157static struct spi_driver ad7314_driver = {
 158        .driver = {
 159                .name = "ad7314",
 160        },
 161        .probe = ad7314_probe,
 162        .remove = ad7314_remove,
 163        .id_table = ad7314_id,
 164};
 165
 166module_spi_driver(ad7314_driver);
 167
 168MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
 169MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital temperature sensor driver");
 170MODULE_LICENSE("GPL v2");
 171