1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Driver for Linear Technology LTC2990 power monitor |
4 | * |
5 | * Copyright (C) 2014 Topic Embedded Products |
6 | * Author: Mike Looijmans <mike.looijmans@topic.nl> |
7 | */ |
8 | |
9 | #include <linux/bitops.h> |
10 | #include <linux/err.h> |
11 | #include <linux/hwmon.h> |
12 | #include <linux/hwmon-sysfs.h> |
13 | #include <linux/i2c.h> |
14 | #include <linux/kernel.h> |
15 | #include <linux/module.h> |
16 | #include <linux/property.h> |
17 | |
18 | #define LTC2990_STATUS 0x00 |
19 | #define LTC2990_CONTROL 0x01 |
20 | #define LTC2990_TRIGGER 0x02 |
21 | #define LTC2990_TINT_MSB 0x04 |
22 | #define LTC2990_V1_MSB 0x06 |
23 | #define LTC2990_V2_MSB 0x08 |
24 | #define LTC2990_V3_MSB 0x0A |
25 | #define LTC2990_V4_MSB 0x0C |
26 | #define LTC2990_VCC_MSB 0x0E |
27 | |
28 | #define LTC2990_IN0 BIT(0) |
29 | #define LTC2990_IN1 BIT(1) |
30 | #define LTC2990_IN2 BIT(2) |
31 | #define LTC2990_IN3 BIT(3) |
32 | #define LTC2990_IN4 BIT(4) |
33 | #define LTC2990_CURR1 BIT(5) |
34 | #define LTC2990_CURR2 BIT(6) |
35 | #define LTC2990_TEMP1 BIT(7) |
36 | #define LTC2990_TEMP2 BIT(8) |
37 | #define LTC2990_TEMP3 BIT(9) |
38 | #define LTC2990_NONE 0 |
39 | #define LTC2990_ALL GENMASK(9, 0) |
40 | |
41 | #define LTC2990_MODE0_SHIFT 0 |
42 | #define LTC2990_MODE0_MASK GENMASK(2, 0) |
43 | #define LTC2990_MODE1_SHIFT 3 |
44 | #define LTC2990_MODE1_MASK GENMASK(1, 0) |
45 | |
46 | /* Enabled measurements for mode bits 2..0 */ |
47 | static const int ltc2990_attrs_ena_0[] = { |
48 | LTC2990_IN1 | LTC2990_IN2 | LTC2990_TEMP3, |
49 | LTC2990_CURR1 | LTC2990_TEMP3, |
50 | LTC2990_CURR1 | LTC2990_IN3 | LTC2990_IN4, |
51 | LTC2990_TEMP2 | LTC2990_IN3 | LTC2990_IN4, |
52 | LTC2990_TEMP2 | LTC2990_CURR2, |
53 | LTC2990_TEMP2 | LTC2990_TEMP3, |
54 | LTC2990_CURR1 | LTC2990_CURR2, |
55 | LTC2990_IN1 | LTC2990_IN2 | LTC2990_IN3 | LTC2990_IN4 |
56 | }; |
57 | |
58 | /* Enabled measurements for mode bits 4..3 */ |
59 | static const int ltc2990_attrs_ena_1[] = { |
60 | LTC2990_NONE, |
61 | LTC2990_TEMP2 | LTC2990_IN1 | LTC2990_CURR1, |
62 | LTC2990_TEMP3 | LTC2990_IN3 | LTC2990_CURR2, |
63 | LTC2990_ALL |
64 | }; |
65 | |
66 | struct ltc2990_data { |
67 | struct i2c_client *i2c; |
68 | u32 mode[2]; |
69 | }; |
70 | |
71 | /* Return the converted value from the given register in uV or mC */ |
72 | static int ltc2990_get_value(struct i2c_client *i2c, int index, int *result) |
73 | { |
74 | int val; |
75 | u8 reg; |
76 | |
77 | switch (index) { |
78 | case LTC2990_IN0: |
79 | reg = LTC2990_VCC_MSB; |
80 | break; |
81 | case LTC2990_IN1: |
82 | case LTC2990_CURR1: |
83 | case LTC2990_TEMP2: |
84 | reg = LTC2990_V1_MSB; |
85 | break; |
86 | case LTC2990_IN2: |
87 | reg = LTC2990_V2_MSB; |
88 | break; |
89 | case LTC2990_IN3: |
90 | case LTC2990_CURR2: |
91 | case LTC2990_TEMP3: |
92 | reg = LTC2990_V3_MSB; |
93 | break; |
94 | case LTC2990_IN4: |
95 | reg = LTC2990_V4_MSB; |
96 | break; |
97 | case LTC2990_TEMP1: |
98 | reg = LTC2990_TINT_MSB; |
99 | break; |
100 | default: |
101 | return -EINVAL; |
102 | } |
103 | |
104 | val = i2c_smbus_read_word_swapped(client: i2c, command: reg); |
105 | if (unlikely(val < 0)) |
106 | return val; |
107 | |
108 | switch (index) { |
109 | case LTC2990_TEMP1: |
110 | case LTC2990_TEMP2: |
111 | case LTC2990_TEMP3: |
112 | /* temp, 0.0625 degrees/LSB */ |
113 | *result = sign_extend32(value: val, index: 12) * 1000 / 16; |
114 | break; |
115 | case LTC2990_CURR1: |
116 | case LTC2990_CURR2: |
117 | /* Vx-Vy, 19.42uV/LSB */ |
118 | *result = sign_extend32(value: val, index: 14) * 1942 / 100; |
119 | break; |
120 | case LTC2990_IN0: |
121 | /* Vcc, 305.18uV/LSB, 2.5V offset */ |
122 | *result = sign_extend32(value: val, index: 14) * 30518 / (100 * 1000) + 2500; |
123 | break; |
124 | case LTC2990_IN1: |
125 | case LTC2990_IN2: |
126 | case LTC2990_IN3: |
127 | case LTC2990_IN4: |
128 | /* Vx, 305.18uV/LSB */ |
129 | *result = sign_extend32(value: val, index: 14) * 30518 / (100 * 1000); |
130 | break; |
131 | default: |
132 | return -EINVAL; /* won't happen, keep compiler happy */ |
133 | } |
134 | |
135 | return 0; |
136 | } |
137 | |
138 | static ssize_t ltc2990_value_show(struct device *dev, |
139 | struct device_attribute *da, char *buf) |
140 | { |
141 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
142 | struct ltc2990_data *data = dev_get_drvdata(dev); |
143 | int value; |
144 | int ret; |
145 | |
146 | ret = ltc2990_get_value(i2c: data->i2c, index: attr->index, result: &value); |
147 | if (unlikely(ret < 0)) |
148 | return ret; |
149 | |
150 | return sysfs_emit(buf, fmt: "%d\n" , value); |
151 | } |
152 | |
153 | static umode_t ltc2990_attrs_visible(struct kobject *kobj, |
154 | struct attribute *a, int n) |
155 | { |
156 | struct device *dev = kobj_to_dev(kobj); |
157 | struct ltc2990_data *data = dev_get_drvdata(dev); |
158 | struct device_attribute *da = |
159 | container_of(a, struct device_attribute, attr); |
160 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
161 | |
162 | int attrs_mask = LTC2990_IN0 | LTC2990_TEMP1 | |
163 | (ltc2990_attrs_ena_0[data->mode[0]] & |
164 | ltc2990_attrs_ena_1[data->mode[1]]); |
165 | |
166 | if (attr->index & attrs_mask) |
167 | return a->mode; |
168 | |
169 | return 0; |
170 | } |
171 | |
172 | static SENSOR_DEVICE_ATTR_RO(temp1_input, ltc2990_value, LTC2990_TEMP1); |
173 | static SENSOR_DEVICE_ATTR_RO(temp2_input, ltc2990_value, LTC2990_TEMP2); |
174 | static SENSOR_DEVICE_ATTR_RO(temp3_input, ltc2990_value, LTC2990_TEMP3); |
175 | static SENSOR_DEVICE_ATTR_RO(curr1_input, ltc2990_value, LTC2990_CURR1); |
176 | static SENSOR_DEVICE_ATTR_RO(curr2_input, ltc2990_value, LTC2990_CURR2); |
177 | static SENSOR_DEVICE_ATTR_RO(in0_input, ltc2990_value, LTC2990_IN0); |
178 | static SENSOR_DEVICE_ATTR_RO(in1_input, ltc2990_value, LTC2990_IN1); |
179 | static SENSOR_DEVICE_ATTR_RO(in2_input, ltc2990_value, LTC2990_IN2); |
180 | static SENSOR_DEVICE_ATTR_RO(in3_input, ltc2990_value, LTC2990_IN3); |
181 | static SENSOR_DEVICE_ATTR_RO(in4_input, ltc2990_value, LTC2990_IN4); |
182 | |
183 | static struct attribute *ltc2990_attrs[] = { |
184 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
185 | &sensor_dev_attr_temp2_input.dev_attr.attr, |
186 | &sensor_dev_attr_temp3_input.dev_attr.attr, |
187 | &sensor_dev_attr_curr1_input.dev_attr.attr, |
188 | &sensor_dev_attr_curr2_input.dev_attr.attr, |
189 | &sensor_dev_attr_in0_input.dev_attr.attr, |
190 | &sensor_dev_attr_in1_input.dev_attr.attr, |
191 | &sensor_dev_attr_in2_input.dev_attr.attr, |
192 | &sensor_dev_attr_in3_input.dev_attr.attr, |
193 | &sensor_dev_attr_in4_input.dev_attr.attr, |
194 | NULL, |
195 | }; |
196 | |
197 | static const struct attribute_group ltc2990_group = { |
198 | .attrs = ltc2990_attrs, |
199 | .is_visible = ltc2990_attrs_visible, |
200 | }; |
201 | __ATTRIBUTE_GROUPS(ltc2990); |
202 | |
203 | static int ltc2990_i2c_probe(struct i2c_client *i2c) |
204 | { |
205 | int ret; |
206 | struct device *hwmon_dev; |
207 | struct ltc2990_data *data; |
208 | |
209 | if (!i2c_check_functionality(adap: i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | |
210 | I2C_FUNC_SMBUS_WORD_DATA)) |
211 | return -ENODEV; |
212 | |
213 | data = devm_kzalloc(dev: &i2c->dev, size: sizeof(struct ltc2990_data), GFP_KERNEL); |
214 | if (unlikely(!data)) |
215 | return -ENOMEM; |
216 | |
217 | data->i2c = i2c; |
218 | |
219 | if (dev_fwnode(&i2c->dev)) { |
220 | ret = device_property_read_u32_array(dev: &i2c->dev, |
221 | propname: "lltc,meas-mode" , |
222 | val: data->mode, nval: 2); |
223 | if (ret < 0) |
224 | return ret; |
225 | |
226 | if (data->mode[0] & ~LTC2990_MODE0_MASK || |
227 | data->mode[1] & ~LTC2990_MODE1_MASK) |
228 | return -EINVAL; |
229 | } else { |
230 | ret = i2c_smbus_read_byte_data(client: i2c, LTC2990_CONTROL); |
231 | if (ret < 0) |
232 | return ret; |
233 | |
234 | data->mode[0] = ret >> LTC2990_MODE0_SHIFT & LTC2990_MODE0_MASK; |
235 | data->mode[1] = ret >> LTC2990_MODE1_SHIFT & LTC2990_MODE1_MASK; |
236 | } |
237 | |
238 | /* Setup continuous mode */ |
239 | ret = i2c_smbus_write_byte_data(client: i2c, LTC2990_CONTROL, |
240 | value: data->mode[0] << LTC2990_MODE0_SHIFT | |
241 | data->mode[1] << LTC2990_MODE1_SHIFT); |
242 | if (ret < 0) { |
243 | dev_err(&i2c->dev, "Error: Failed to set control mode.\n" ); |
244 | return ret; |
245 | } |
246 | /* Trigger once to start continuous conversion */ |
247 | ret = i2c_smbus_write_byte_data(client: i2c, LTC2990_TRIGGER, value: 1); |
248 | if (ret < 0) { |
249 | dev_err(&i2c->dev, "Error: Failed to start acquisition.\n" ); |
250 | return ret; |
251 | } |
252 | |
253 | hwmon_dev = devm_hwmon_device_register_with_groups(dev: &i2c->dev, |
254 | name: i2c->name, |
255 | drvdata: data, |
256 | groups: ltc2990_groups); |
257 | |
258 | return PTR_ERR_OR_ZERO(ptr: hwmon_dev); |
259 | } |
260 | |
261 | static const struct i2c_device_id ltc2990_i2c_id[] = { |
262 | { "ltc2990" , 0 }, |
263 | {} |
264 | }; |
265 | MODULE_DEVICE_TABLE(i2c, ltc2990_i2c_id); |
266 | |
267 | static struct i2c_driver ltc2990_i2c_driver = { |
268 | .driver = { |
269 | .name = "ltc2990" , |
270 | }, |
271 | .probe = ltc2990_i2c_probe, |
272 | .id_table = ltc2990_i2c_id, |
273 | }; |
274 | |
275 | module_i2c_driver(ltc2990_i2c_driver); |
276 | |
277 | MODULE_DESCRIPTION("LTC2990 Sensor Driver" ); |
278 | MODULE_AUTHOR("Topic Embedded Products" ); |
279 | MODULE_LICENSE("GPL v2" ); |
280 | |