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