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
  20/*
  21 * AD7314 temperature masks
  22 */
  23#define AD7314_TEMP_MASK                0x7FE0
  24#define AD7314_TEMP_SHIFT               5
  25
  26/*
  27 * ADT7301 and ADT7302 temperature masks
  28 */
  29#define ADT7301_TEMP_MASK               0x3FFF
  30
  31enum ad7314_variant {
  32        adt7301,
  33        adt7302,
  34        ad7314,
  35};
  36
  37struct ad7314_data {
  38        struct spi_device       *spi_dev;
  39        struct device           *hwmon_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 = (data << 6) >> 6;
  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 = (data << 2) >> 2;
  82
  83                return sprintf(buf, "%d\n",
  84                               DIV_ROUND_CLOSEST(data * 3125, 100));
  85        default:
  86                return -EINVAL;
  87        }
  88}
  89
  90static ssize_t ad7314_show_name(struct device *dev,
  91                                struct device_attribute *devattr, char *buf)
  92{
  93        return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
  94}
  95
  96static DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL);
  97static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
  98                          ad7314_show_temperature, NULL, 0);
  99
 100static struct attribute *ad7314_attributes[] = {
 101        &dev_attr_name.attr,
 102        &sensor_dev_attr_temp1_input.dev_attr.attr,
 103        NULL,
 104};
 105
 106static const struct attribute_group ad7314_group = {
 107        .attrs = ad7314_attributes,
 108};
 109
 110static int __devinit ad7314_probe(struct spi_device *spi_dev)
 111{
 112        int ret;
 113        struct ad7314_data *chip;
 114
 115        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
 116        if (chip == NULL) {
 117                ret = -ENOMEM;
 118                goto error_ret;
 119        }
 120        dev_set_drvdata(&spi_dev->dev, chip);
 121
 122        ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
 123        if (ret < 0)
 124                goto error_free_chip;
 125        chip->hwmon_dev = hwmon_device_register(&spi_dev->dev);
 126        if (IS_ERR(chip->hwmon_dev)) {
 127                ret = PTR_ERR(chip->hwmon_dev);
 128                goto error_remove_group;
 129        }
 130        chip->spi_dev = spi_dev;
 131
 132        return 0;
 133error_remove_group:
 134        sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
 135error_free_chip:
 136        kfree(chip);
 137error_ret:
 138        return ret;
 139}
 140
 141static int __devexit ad7314_remove(struct spi_device *spi_dev)
 142{
 143        struct ad7314_data *chip = dev_get_drvdata(&spi_dev->dev);
 144
 145        hwmon_device_unregister(chip->hwmon_dev);
 146        sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
 147        kfree(chip);
 148
 149        return 0;
 150}
 151
 152static const struct spi_device_id ad7314_id[] = {
 153        { "adt7301", adt7301 },
 154        { "adt7302", adt7302 },
 155        { "ad7314", ad7314 },
 156        { }
 157};
 158MODULE_DEVICE_TABLE(spi, ad7314_id);
 159
 160static struct spi_driver ad7314_driver = {
 161        .driver = {
 162                .name = "ad7314",
 163                .owner = THIS_MODULE,
 164        },
 165        .probe = ad7314_probe,
 166        .remove = __devexit_p(ad7314_remove),
 167        .id_table = ad7314_id,
 168};
 169
 170module_spi_driver(ad7314_driver);
 171
 172MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
 173MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital"
 174                        " temperature sensor driver");
 175MODULE_LICENSE("GPL v2");
 176
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.