Commit | Line | Data |
---|---|---|
df922703 ML |
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 */ | |
38 | static 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 */ | |
47 | static 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 | ||
78 | static 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 | ||
92 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ltc2990_show_value, NULL, | |
93 | LTC2990_TINT_MSB); | |
94 | static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2990_show_value, NULL, | |
95 | LTC2990_V1_MSB); | |
96 | static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc2990_show_value, NULL, | |
97 | LTC2990_V3_MSB); | |
98 | static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ltc2990_show_value, NULL, | |
99 | LTC2990_VCC_MSB); | |
100 | ||
101 | static 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 | }; | |
108 | ATTRIBUTE_GROUPS(ltc2990); | |
109 | ||
110 | static 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 | ||
143 | static const struct i2c_device_id ltc2990_i2c_id[] = { | |
144 | { "ltc2990", 0 }, | |
145 | {} | |
146 | }; | |
147 | MODULE_DEVICE_TABLE(i2c, ltc2990_i2c_id); | |
148 | ||
149 | static 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 | ||
157 | module_i2c_driver(ltc2990_i2c_driver); | |
158 | ||
159 | MODULE_DESCRIPTION("LTC2990 Sensor Driver"); | |
160 | MODULE_AUTHOR("Topic Embedded Products"); | |
161 | MODULE_LICENSE("GPL v2"); |