aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Looijmans <mike.looijmans@topic.nl>2016-01-15 04:54:59 -0500
committerGuenter Roeck <linux@roeck-us.net>2016-03-05 09:25:34 -0500
commitdf922703574ebe9035045f7c7242a0ec0e11b980 (patch)
tree1c9ffb5cdc48f11f61140c7db2555f2dffacb774
parentc32f5eff2db51f0126b0a4e42bdefea2d9d2872e (diff)
hwmon: Add LTC2990 sensor driver
This adds support for the Linear Technology LTC2990 I2C System Monitor. The LTC2990 supports a combination of voltage, current and temperature monitoring. This driver currently only supports reading two currents by measuring two differential voltages across series resistors, in addition to the Vcc supply voltage and internal temperature. This is sufficient to support the Topic Miami SOM which uses this chip to monitor the currents flowing into the FPGA and the CPU parts. Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r--Documentation/hwmon/ltc299043
-rw-r--r--drivers/hwmon/Kconfig14
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/ltc2990.c161
4 files changed, 219 insertions, 0 deletions
diff --git a/Documentation/hwmon/ltc2990 b/Documentation/hwmon/ltc2990
new file mode 100644
index 000000000000..c25211e90bdc
--- /dev/null
+++ b/Documentation/hwmon/ltc2990
@@ -0,0 +1,43 @@
1Kernel driver ltc2990
2=====================
3
4Supported chips:
5 * Linear Technology LTC2990
6 Prefix: 'ltc2990'
7 Addresses scanned: -
8 Datasheet: http://www.linear.com/product/ltc2990
9
10Author: Mike Looijmans <mike.looijmans@topic.nl>
11
12
13Description
14-----------
15
16LTC2990 is a Quad I2C Voltage, Current and Temperature Monitor.
17The chip's inputs can measure 4 voltages, or two inputs together (1+2 and 3+4)
18can be combined to measure a differential voltage, which is typically used to
19measure current through a series resistor, or a temperature.
20
21This driver currently uses the 2x differential mode only. In order to support
22other modes, the driver will need to be expanded.
23
24
25Usage Notes
26-----------
27
28This driver does not probe for PMBus devices. You will have to instantiate
29devices explicitly.
30
31
32Sysfs attributes
33----------------
34
35The "curr*_input" measurements actually report the voltage drop across the
36input pins in microvolts. This is equivalent to the current through a 1mOhm
37sense resistor. Divide the reported value by the actual sense resistor value
38in mOhm to get the actual value.
39
40in0_input Voltage at Vcc pin in millivolt (range 2.5V to 5V)
41temp1_input Internal chip temperature in millidegrees Celcius
42curr1_input Current in mA across v1-v2 assuming a 1mOhm sense resistor.
43curr2_input Current in mA across v3-v4 assuming a 1mOhm sense resistor.
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 60fb80bd353d..852c8a85e1e8 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -685,6 +685,20 @@ config SENSORS_LTC2945
685 This driver can also be built as a module. If so, the module will 685 This driver can also be built as a module. If so, the module will
686 be called ltc2945. 686 be called ltc2945.
687 687
688config SENSORS_LTC2990
689 tristate "Linear Technology LTC2990 (current monitoring mode only)"
690 depends on I2C
691 help
692 If you say yes here you get support for Linear Technology LTC2990
693 I2C System Monitor. The LTC2990 supports a combination of voltage,
694 current and temperature monitoring, but in addition to the Vcc supply
695 voltage and chip temperature, this driver currently only supports
696 reading two currents by measuring two differential voltages across
697 series resistors.
698
699 This driver can also be built as a module. If so, the module will
700 be called ltc2990.
701
688config SENSORS_LTC4151 702config SENSORS_LTC4151
689 tristate "Linear Technology LTC4151" 703 tristate "Linear Technology LTC4151"
690 depends on I2C 704 depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index cfc09711810c..a7ecaf2f29aa 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -100,6 +100,7 @@ obj-$(CONFIG_SENSORS_LM95234) += lm95234.o
100obj-$(CONFIG_SENSORS_LM95241) += lm95241.o 100obj-$(CONFIG_SENSORS_LM95241) += lm95241.o
101obj-$(CONFIG_SENSORS_LM95245) += lm95245.o 101obj-$(CONFIG_SENSORS_LM95245) += lm95245.o
102obj-$(CONFIG_SENSORS_LTC2945) += ltc2945.o 102obj-$(CONFIG_SENSORS_LTC2945) += ltc2945.o
103obj-$(CONFIG_SENSORS_LTC2990) += ltc2990.o
103obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o 104obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o
104obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o 105obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o
105obj-$(CONFIG_SENSORS_LTC4222) += ltc4222.o 106obj-$(CONFIG_SENSORS_LTC4222) += ltc4222.o
diff --git a/drivers/hwmon/ltc2990.c b/drivers/hwmon/ltc2990.c
new file mode 100644
index 000000000000..8f8fe059ab48
--- /dev/null
+++ b/drivers/hwmon/ltc2990.c
@@ -0,0 +1,161 @@
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");