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        u16 rx ____cacheline_aligned;
  41};
  42
  43static int ad7314_spi_read(struct ad7314_data *chip)
  44{
  45        int ret;
  46
  47        ret = spi_read(chip->spi_dev, (u8 *)&chip->rx, sizeof(chip->rx));
  48        if (ret < 0) {
  49                dev_err(&chip->spi_dev->dev, "SPI read error\n");
  50                return ret;
  51        }
  52
  53        return be16_to_cpu(chip->rx);
  54}
  55
  56static ssize_t ad7314_show_temperature(struct device *dev,
  57                struct device_attribute *attr,
  58                char *buf)
  59{
  60        struct ad7314_data *chip = dev_get_drvdata(dev);
  61        s16 data;
  62        int ret;
  63
  64        ret = ad7314_spi_read(chip);
  65        if (ret < 0)
  66                return ret;
  67        switch (spi_get_device_id(chip->spi_dev)->driver_data) {
  68        case ad7314:
  69                data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT;
  70                data = sign_extend32(data, 9);
  71
  72                return sprintf(buf, "%d\n", 250 * data);
  73        case adt7301:
  74        case adt7302:
  75                /*
  76                 * Documented as a 13 bit twos complement register
  77                 * with a sign bit - which is a 14 bit 2's complement
  78                 * register.  1lsb - 31.25 milli degrees centigrade
  79                 */
  80                data = ret & ADT7301_TEMP_MASK;
  81                data = sign_extend32(data, 13);
  82
  83                return sprintf(buf, "%d\n",
  84                               DIV_ROUND_CLOSEST(data * 3125, 100));
  85        default:
  86                return -EINVAL;
  87        }
  88}
  89
  90static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
  91                          ad7314_show_temperature, NULL, 0);
  92
  93static struct attribute *ad7314_attrs[] = {
  94        &sensor_dev_attr_temp1_input.dev_attr.attr,
  95        NULL,
  96};
  97
  98ATTRIBUTE_GROUPS(ad7314);
  99
 100static int ad7314_probe(struct spi_device *spi_dev)
 101{
 102        struct ad7314_data *chip;
 103        struct device *hwmon_dev;
 104
 105        chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL);
 106        if (chip == NULL)
 107                return -ENOMEM;
 108
 109        chip->spi_dev = spi_dev;
 110        hwmon_dev = devm_hwmon_device_register_with_groups(&spi_dev->dev,
 111                                                           spi_dev->modalias,
 112                                                           chip, ad7314_groups);
 113        return PTR_ERR_OR_ZERO(hwmon_dev);
 114}
 115
 116static const struct spi_device_id ad7314_id[] = {
 117        { "adt7301", adt7301 },
 118        { "adt7302", adt7302 },
 119        { "ad7314", ad7314 },
 120        { }
 121};
 122MODULE_DEVICE_TABLE(spi, ad7314_id);
 123
 124static struct spi_driver ad7314_driver = {
 125        .driver = {
 126                .name = "ad7314",
 127        },
 128        .probe = ad7314_probe,
 129        .id_table = ad7314_id,
 130};
 131
 132module_spi_driver(ad7314_driver);
 133
 134MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
 135MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital temperature sensor driver");
 136MODULE_LICENSE("GPL v2");
 137