blob: e320d212ac270d5ddf6aba2f91d18d400b29af2b [file] [log] [blame]
Mike Looijmansdf922702016-01-15 10:54:59 +01001/*
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
Tom Levensa6282d12017-07-03 06:28:58 +020014#include <linux/bitops.h>
Mike Looijmansdf922702016-01-15 10:54:59 +010015#include <linux/err.h>
16#include <linux/hwmon.h>
17#include <linux/hwmon-sysfs.h>
18#include <linux/i2c.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21
22#define LTC2990_STATUS 0x00
23#define LTC2990_CONTROL 0x01
24#define LTC2990_TRIGGER 0x02
25#define LTC2990_TINT_MSB 0x04
26#define LTC2990_V1_MSB 0x06
27#define LTC2990_V2_MSB 0x08
28#define LTC2990_V3_MSB 0x0A
29#define LTC2990_V4_MSB 0x0C
30#define LTC2990_VCC_MSB 0x0E
31
32#define LTC2990_CONTROL_KELVIN BIT(7)
33#define LTC2990_CONTROL_SINGLE BIT(6)
34#define LTC2990_CONTROL_MEASURE_ALL (0x3 << 3)
35#define LTC2990_CONTROL_MODE_CURRENT 0x06
36#define LTC2990_CONTROL_MODE_VOLTAGE 0x07
37
Mike Looijmansdf922702016-01-15 10:54:59 +010038/* Return the converted value from the given register in uV or mC */
39static int ltc2990_get_value(struct i2c_client *i2c, u8 reg, int *result)
40{
41 int val;
42
43 val = i2c_smbus_read_word_swapped(i2c, reg);
44 if (unlikely(val < 0))
45 return val;
46
47 switch (reg) {
48 case LTC2990_TINT_MSB:
49 /* internal temp, 0.0625 degrees/LSB, 13-bit */
Tom Levensa6282d12017-07-03 06:28:58 +020050 *result = sign_extend32(val, 12) * 1000 / 16;
Mike Looijmansdf922702016-01-15 10:54:59 +010051 break;
52 case LTC2990_V1_MSB:
53 case LTC2990_V3_MSB:
54 /* Vx-Vy, 19.42uV/LSB. Depends on mode. */
Tom Levensa6282d12017-07-03 06:28:58 +020055 *result = sign_extend32(val, 14) * 1942 / 100;
Mike Looijmansdf922702016-01-15 10:54:59 +010056 break;
57 case LTC2990_VCC_MSB:
58 /* Vcc, 305.18μV/LSB, 2.5V offset */
Tom Levensa6282d12017-07-03 06:28:58 +020059 *result = sign_extend32(val, 14) * 30518 / (100 * 1000) + 2500;
Mike Looijmansdf922702016-01-15 10:54:59 +010060 break;
61 default:
62 return -EINVAL; /* won't happen, keep compiler happy */
63 }
64
65 return 0;
66}
67
68static ssize_t ltc2990_show_value(struct device *dev,
69 struct device_attribute *da, char *buf)
70{
71 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
72 int value;
73 int ret;
74
75 ret = ltc2990_get_value(dev_get_drvdata(dev), attr->index, &value);
76 if (unlikely(ret < 0))
77 return ret;
78
79 return snprintf(buf, PAGE_SIZE, "%d\n", value);
80}
81
82static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ltc2990_show_value, NULL,
83 LTC2990_TINT_MSB);
84static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2990_show_value, NULL,
85 LTC2990_V1_MSB);
86static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc2990_show_value, NULL,
87 LTC2990_V3_MSB);
88static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ltc2990_show_value, NULL,
89 LTC2990_VCC_MSB);
90
91static struct attribute *ltc2990_attrs[] = {
92 &sensor_dev_attr_temp1_input.dev_attr.attr,
93 &sensor_dev_attr_curr1_input.dev_attr.attr,
94 &sensor_dev_attr_curr2_input.dev_attr.attr,
95 &sensor_dev_attr_in0_input.dev_attr.attr,
96 NULL,
97};
98ATTRIBUTE_GROUPS(ltc2990);
99
100static int ltc2990_i2c_probe(struct i2c_client *i2c,
101 const struct i2c_device_id *id)
102{
103 int ret;
104 struct device *hwmon_dev;
105
106 if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
107 I2C_FUNC_SMBUS_WORD_DATA))
108 return -ENODEV;
109
110 /* Setup continuous mode, current monitor */
111 ret = i2c_smbus_write_byte_data(i2c, LTC2990_CONTROL,
112 LTC2990_CONTROL_MEASURE_ALL |
113 LTC2990_CONTROL_MODE_CURRENT);
114 if (ret < 0) {
115 dev_err(&i2c->dev, "Error: Failed to set control mode.\n");
116 return ret;
117 }
118 /* Trigger once to start continuous conversion */
119 ret = i2c_smbus_write_byte_data(i2c, LTC2990_TRIGGER, 1);
120 if (ret < 0) {
121 dev_err(&i2c->dev, "Error: Failed to start acquisition.\n");
122 return ret;
123 }
124
125 hwmon_dev = devm_hwmon_device_register_with_groups(&i2c->dev,
126 i2c->name,
127 i2c,
128 ltc2990_groups);
129
130 return PTR_ERR_OR_ZERO(hwmon_dev);
131}
132
133static const struct i2c_device_id ltc2990_i2c_id[] = {
134 { "ltc2990", 0 },
135 {}
136};
137MODULE_DEVICE_TABLE(i2c, ltc2990_i2c_id);
138
139static struct i2c_driver ltc2990_i2c_driver = {
140 .driver = {
141 .name = "ltc2990",
142 },
143 .probe = ltc2990_i2c_probe,
144 .id_table = ltc2990_i2c_id,
145};
146
147module_i2c_driver(ltc2990_i2c_driver);
148
149MODULE_DESCRIPTION("LTC2990 Sensor Driver");
150MODULE_AUTHOR("Topic Embedded Products");
151MODULE_LICENSE("GPL v2");