linux/drivers/hwmon/ltc2990.c
<<
>>
Prefs
   1/*
   2 * Driver for Linear Technology LTC2990 power monitor
   3 *
   4 * Copyright (C) 2014 Topic Embedded Products
   5 * Author: Mike Looijmans <mike.looijmans@topic.nl>
   6 *
   7 * License: GPLv2
   8 *
   9 * This driver assumes the chip is wired as a dual current monitor, and
  10 * reports the voltage drop across two series resistors. It also reports
  11 * the chip's internal temperature and Vcc power supply voltage.
  12 */
  13
  14#include <linux/err.h>
  15#include <linux/hwmon.h>
  16#include <linux/hwmon-sysfs.h>
  17#include <linux/i2c.h>
  18#include <linux/kernel.h>
  19#include <linux/module.h>
  20
  21#define LTC2990_STATUS  0x00
  22#define LTC2990_CONTROL 0x01
  23#define LTC2990_TRIGGER 0x02
  24#define LTC2990_TINT_MSB        0x04
  25#define LTC2990_V1_MSB  0x06
  26#define LTC2990_V2_MSB  0x08
  27#define LTC2990_V3_MSB  0x0A
  28#define LTC2990_V4_MSB  0x0C
  29#define LTC2990_VCC_MSB 0x0E
  30
  31#define LTC2990_CONTROL_KELVIN          BIT(7)
  32#define LTC2990_CONTROL_SINGLE          BIT(6)
  33#define LTC2990_CONTROL_MEASURE_ALL     (0x3 << 3)
  34#define LTC2990_CONTROL_MODE_CURRENT    0x06
  35#define LTC2990_CONTROL_MODE_VOLTAGE    0x07
  36
  37/* convert raw register value to sign-extended integer in 16-bit range */
  38static int ltc2990_voltage_to_int(int raw)
  39{
  40        if (raw & BIT(14))
  41                return -(0x4000 - (raw & 0x3FFF)) << 2;
  42        else
  43                return (raw & 0x3FFF) << 2;
  44}
  45
  46/* Return the converted value from the given register in uV or mC */
  47static int ltc2990_get_value(struct i2c_client *i2c, u8 reg, int *result)
  48{
  49        int val;
  50
  51        val = i2c_smbus_read_word_swapped(i2c, reg);
  52        if (unlikely(val < 0))
  53                return val;
  54
  55        switch (reg) {
  56        case LTC2990_TINT_MSB:
  57                /* internal temp, 0.0625 degrees/LSB, 13-bit  */
  58                val = (val & 0x1FFF) << 3;
  59                *result = (val * 1000) >> 7;
  60                break;
  61        case LTC2990_V1_MSB:
  62        case LTC2990_V3_MSB:
  63                 /* Vx-Vy, 19.42uV/LSB. Depends on mode. */
  64                *result = ltc2990_voltage_to_int(val) * 1942 / (4 * 100);
  65                break;
  66        case LTC2990_VCC_MSB:
  67                /* Vcc, 305.18μV/LSB, 2.5V offset */
  68                *result = (ltc2990_voltage_to_int(val) * 30518 /
  69                           (4 * 100 * 1000)) + 2500;
  70                break;
  71        default:
  72                return -EINVAL; /* won't happen, keep compiler happy */
  73        }
  74
  75        return 0;
  76}
  77
  78static ssize_t ltc2990_show_value(struct device *dev,
  79                                  struct device_attribute *da, char *buf)
  80{
  81        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  82        int value;
  83        int ret;
  84
  85        ret = ltc2990_get_value(dev_get_drvdata(dev), attr->index, &value);
  86        if (unlikely(ret < 0))
  87                return ret;
  88
  89        return snprintf(buf, PAGE_SIZE, "%d\n", value);
  90}
  91
  92static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ltc2990_show_value, NULL,
  93                          LTC2990_TINT_MSB);
  94static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2990_show_value, NULL,
  95                          LTC2990_V1_MSB);
  96static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc2990_show_value, NULL,
  97                          LTC2990_V3_MSB);
  98static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ltc2990_show_value, NULL,
  99                          LTC2990_VCC_MSB);
 100
 101static struct attribute *ltc2990_attrs[] = {
 102        &sensor_dev_attr_temp1_input.dev_attr.attr,
 103        &sensor_dev_attr_curr1_input.dev_attr.attr,
 104        &sensor_dev_attr_curr2_input.dev_attr.attr,
 105        &sensor_dev_attr_in0_input.dev_attr.attr,
 106        NULL,
 107};
 108ATTRIBUTE_GROUPS(ltc2990);
 109
 110static int ltc2990_i2c_probe(struct i2c_client *i2c,
 111                             const struct i2c_device_id *id)
 112{
 113        int ret;
 114        struct device *hwmon_dev;
 115
 116        if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
 117                                     I2C_FUNC_SMBUS_WORD_DATA))
 118                return -ENODEV;
 119
 120        /* Setup continuous mode, current monitor */
 121        ret = i2c_smbus_write_byte_data(i2c, LTC2990_CONTROL,
 122                                        LTC2990_CONTROL_MEASURE_ALL |
 123                                        LTC2990_CONTROL_MODE_CURRENT);
 124        if (ret < 0) {
 125                dev_err(&i2c->dev, "Error: Failed to set control mode.\n");
 126                return ret;
 127        }
 128        /* Trigger once to start continuous conversion */
 129        ret = i2c_smbus_write_byte_data(i2c, LTC2990_TRIGGER, 1);
 130        if (ret < 0) {
 131                dev_err(&i2c->dev, "Error: Failed to start acquisition.\n");
 132                return ret;
 133        }
 134
 135        hwmon_dev = devm_hwmon_device_register_with_groups(&i2c->dev,
 136                                                           i2c->name,
 137                                                           i2c,
 138                                                           ltc2990_groups);
 139
 140        return PTR_ERR_OR_ZERO(hwmon_dev);
 141}
 142
 143static const struct i2c_device_id ltc2990_i2c_id[] = {
 144        { "ltc2990", 0 },
 145        {}
 146};
 147MODULE_DEVICE_TABLE(i2c, ltc2990_i2c_id);
 148
 149static struct i2c_driver ltc2990_i2c_driver = {
 150        .driver = {
 151                .name = "ltc2990",
 152        },
 153        .probe    = ltc2990_i2c_probe,
 154        .id_table = ltc2990_i2c_id,
 155};
 156
 157module_i2c_driver(ltc2990_i2c_driver);
 158
 159MODULE_DESCRIPTION("LTC2990 Sensor Driver");
 160MODULE_AUTHOR("Topic Embedded Products");
 161MODULE_LICENSE("GPL v2");
 162