1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2023 Analog Devices, Inc. |
4 | * Author: Antoniu Miclaus <antoniu.miclaus@analog.com> |
5 | */ |
6 | |
7 | #include <linux/bitops.h> |
8 | #include <linux/err.h> |
9 | #include <linux/hwmon.h> |
10 | #include <linux/i2c.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/module.h> |
13 | #include <linux/property.h> |
14 | #include <linux/regmap.h> |
15 | #include <linux/regulator/consumer.h> |
16 | |
17 | #define LTC2991_STATUS_LOW 0x00 |
18 | #define LTC2991_CH_EN_TRIGGER 0x01 |
19 | #define LTC2991_V1_V4_CTRL 0x06 |
20 | #define LTC2991_V5_V8_CTRL 0x07 |
21 | #define LTC2991_PWM_TH_LSB_T_INT 0x08 |
22 | #define LTC2991_PWM_TH_MSB 0x09 |
23 | #define LTC2991_CHANNEL_V_MSB(x) (0x0A + ((x) * 2)) |
24 | #define LTC2991_CHANNEL_T_MSB(x) (0x0A + ((x) * 4)) |
25 | #define LTC2991_CHANNEL_C_MSB(x) (0x0C + ((x) * 4)) |
26 | #define LTC2991_T_INT_MSB 0x1A |
27 | #define LTC2991_VCC_MSB 0x1C |
28 | |
29 | #define LTC2991_V7_V8_EN BIT(7) |
30 | #define LTC2991_V5_V6_EN BIT(6) |
31 | #define LTC2991_V3_V4_EN BIT(5) |
32 | #define LTC2991_V1_V2_EN BIT(4) |
33 | #define LTC2991_T_INT_VCC_EN BIT(3) |
34 | |
35 | #define LTC2991_V3_V4_FILT_EN BIT(7) |
36 | #define LTC2991_V3_V4_TEMP_EN BIT(5) |
37 | #define LTC2991_V3_V4_DIFF_EN BIT(4) |
38 | #define LTC2991_V1_V2_FILT_EN BIT(3) |
39 | #define LTC2991_V1_V2_TEMP_EN BIT(1) |
40 | #define LTC2991_V1_V2_DIFF_EN BIT(0) |
41 | |
42 | #define LTC2991_V7_V8_FILT_EN BIT(7) |
43 | #define LTC2991_V7_V8_TEMP_EN BIT(5) |
44 | #define LTC2991_V7_V8_DIFF_EN BIT(4) |
45 | #define LTC2991_V5_V6_FILT_EN BIT(7) |
46 | #define LTC2991_V5_V6_TEMP_EN BIT(5) |
47 | #define LTC2991_V5_V6_DIFF_EN BIT(4) |
48 | |
49 | #define LTC2991_REPEAT_ACQ_EN BIT(4) |
50 | #define LTC2991_T_INT_FILT_EN BIT(3) |
51 | |
52 | #define LTC2991_MAX_CHANNEL 4 |
53 | #define LTC2991_T_INT_CH_NR 4 |
54 | #define LTC2991_VCC_CH_NR 0 |
55 | |
56 | struct ltc2991_state { |
57 | struct regmap *regmap; |
58 | u32 r_sense_uohm[LTC2991_MAX_CHANNEL]; |
59 | bool temp_en[LTC2991_MAX_CHANNEL]; |
60 | }; |
61 | |
62 | static int ltc2991_read_reg(struct ltc2991_state *st, u8 addr, u8 reg_len, |
63 | int *val) |
64 | { |
65 | __be16 regvals; |
66 | int ret; |
67 | |
68 | if (reg_len < 2) |
69 | return regmap_read(map: st->regmap, reg: addr, val); |
70 | |
71 | ret = regmap_bulk_read(map: st->regmap, reg: addr, val: ®vals, val_count: reg_len); |
72 | if (ret) |
73 | return ret; |
74 | |
75 | *val = be16_to_cpu(regvals); |
76 | |
77 | return 0; |
78 | } |
79 | |
80 | static int ltc2991_get_voltage(struct ltc2991_state *st, u32 reg, long *val) |
81 | { |
82 | int reg_val, ret, offset = 0; |
83 | |
84 | ret = ltc2991_read_reg(st, addr: reg, reg_len: 2, val: ®_val); |
85 | if (ret) |
86 | return ret; |
87 | |
88 | if (reg == LTC2991_VCC_MSB) |
89 | /* Vcc 2.5V offset */ |
90 | offset = 2500; |
91 | |
92 | /* Vx, 305.18uV/LSB */ |
93 | *val = DIV_ROUND_CLOSEST(sign_extend32(reg_val, 14) * 30518, |
94 | 1000 * 100) + offset; |
95 | |
96 | return 0; |
97 | } |
98 | |
99 | static int ltc2991_read_in(struct device *dev, u32 attr, int channel, long *val) |
100 | { |
101 | struct ltc2991_state *st = dev_get_drvdata(dev); |
102 | u32 reg; |
103 | |
104 | switch (attr) { |
105 | case hwmon_in_input: |
106 | if (channel == LTC2991_VCC_CH_NR) |
107 | reg = LTC2991_VCC_MSB; |
108 | else |
109 | reg = LTC2991_CHANNEL_V_MSB(channel - 1); |
110 | |
111 | return ltc2991_get_voltage(st, reg, val); |
112 | default: |
113 | return -EOPNOTSUPP; |
114 | } |
115 | } |
116 | |
117 | static int ltc2991_get_curr(struct ltc2991_state *st, u32 reg, int channel, |
118 | long *val) |
119 | { |
120 | int reg_val, ret; |
121 | |
122 | ret = ltc2991_read_reg(st, addr: reg, reg_len: 2, val: ®_val); |
123 | if (ret) |
124 | return ret; |
125 | |
126 | /* Vx-Vy, 19.075uV/LSB */ |
127 | *val = DIV_ROUND_CLOSEST(sign_extend32(reg_val, 14) * 19075, |
128 | st->r_sense_uohm[channel]); |
129 | |
130 | return 0; |
131 | } |
132 | |
133 | static int ltc2991_read_curr(struct device *dev, u32 attr, int channel, |
134 | long *val) |
135 | { |
136 | struct ltc2991_state *st = dev_get_drvdata(dev); |
137 | u32 reg; |
138 | |
139 | switch (attr) { |
140 | case hwmon_curr_input: |
141 | reg = LTC2991_CHANNEL_C_MSB(channel); |
142 | return ltc2991_get_curr(st, reg, channel, val); |
143 | default: |
144 | return -EOPNOTSUPP; |
145 | } |
146 | } |
147 | |
148 | static int ltc2991_get_temp(struct ltc2991_state *st, u32 reg, int channel, |
149 | long *val) |
150 | { |
151 | int reg_val, ret; |
152 | |
153 | ret = ltc2991_read_reg(st, addr: reg, reg_len: 2, val: ®_val); |
154 | if (ret) |
155 | return ret; |
156 | |
157 | /* Temp LSB = 0.0625 Degrees */ |
158 | *val = DIV_ROUND_CLOSEST(sign_extend32(reg_val, 12) * 1000, 16); |
159 | |
160 | return 0; |
161 | } |
162 | |
163 | static int ltc2991_read_temp(struct device *dev, u32 attr, int channel, |
164 | long *val) |
165 | { |
166 | struct ltc2991_state *st = dev_get_drvdata(dev); |
167 | u32 reg; |
168 | |
169 | switch (attr) { |
170 | case hwmon_temp_input: |
171 | if (channel == LTC2991_T_INT_CH_NR) |
172 | reg = LTC2991_T_INT_MSB; |
173 | else |
174 | reg = LTC2991_CHANNEL_T_MSB(channel); |
175 | |
176 | return ltc2991_get_temp(st, reg, channel, val); |
177 | default: |
178 | return -EOPNOTSUPP; |
179 | } |
180 | } |
181 | |
182 | static int ltc2991_read(struct device *dev, enum hwmon_sensor_types type, |
183 | u32 attr, int channel, long *val) |
184 | { |
185 | switch (type) { |
186 | case hwmon_in: |
187 | return ltc2991_read_in(dev, attr, channel, val); |
188 | case hwmon_curr: |
189 | return ltc2991_read_curr(dev, attr, channel, val); |
190 | case hwmon_temp: |
191 | return ltc2991_read_temp(dev, attr, channel, val); |
192 | default: |
193 | return -EOPNOTSUPP; |
194 | } |
195 | } |
196 | |
197 | static umode_t ltc2991_is_visible(const void *data, |
198 | enum hwmon_sensor_types type, u32 attr, |
199 | int channel) |
200 | { |
201 | const struct ltc2991_state *st = data; |
202 | |
203 | switch (type) { |
204 | case hwmon_in: |
205 | switch (attr) { |
206 | case hwmon_in_input: |
207 | if (channel == LTC2991_VCC_CH_NR) |
208 | return 0444; |
209 | if (st->temp_en[(channel - 1) / 2]) |
210 | break; |
211 | if (channel % 2) |
212 | return 0444; |
213 | if (!st->r_sense_uohm[(channel - 1) / 2]) |
214 | return 0444; |
215 | } |
216 | break; |
217 | case hwmon_curr: |
218 | switch (attr) { |
219 | case hwmon_curr_input: |
220 | if (st->r_sense_uohm[channel]) |
221 | return 0444; |
222 | break; |
223 | } |
224 | break; |
225 | case hwmon_temp: |
226 | switch (attr) { |
227 | case hwmon_temp_input: |
228 | if (st->temp_en[channel] || |
229 | channel == LTC2991_T_INT_CH_NR) |
230 | return 0444; |
231 | break; |
232 | } |
233 | break; |
234 | default: |
235 | break; |
236 | } |
237 | |
238 | return 0; |
239 | } |
240 | |
241 | static const struct hwmon_ops ltc2991_hwmon_ops = { |
242 | .is_visible = ltc2991_is_visible, |
243 | .read = ltc2991_read, |
244 | }; |
245 | |
246 | static const struct hwmon_channel_info *ltc2991_info[] = { |
247 | HWMON_CHANNEL_INFO(temp, |
248 | HWMON_T_INPUT, |
249 | HWMON_T_INPUT, |
250 | HWMON_T_INPUT, |
251 | HWMON_T_INPUT, |
252 | HWMON_T_INPUT |
253 | ), |
254 | HWMON_CHANNEL_INFO(curr, |
255 | HWMON_C_INPUT, |
256 | HWMON_C_INPUT, |
257 | HWMON_C_INPUT, |
258 | HWMON_C_INPUT |
259 | ), |
260 | HWMON_CHANNEL_INFO(in, |
261 | HWMON_I_INPUT, |
262 | HWMON_I_INPUT, |
263 | HWMON_I_INPUT, |
264 | HWMON_I_INPUT, |
265 | HWMON_I_INPUT, |
266 | HWMON_I_INPUT, |
267 | HWMON_I_INPUT, |
268 | HWMON_I_INPUT, |
269 | HWMON_I_INPUT |
270 | ), |
271 | NULL |
272 | }; |
273 | |
274 | static const struct hwmon_chip_info ltc2991_chip_info = { |
275 | .ops = <c2991_hwmon_ops, |
276 | .info = ltc2991_info, |
277 | }; |
278 | |
279 | static const struct regmap_config ltc2991_regmap_config = { |
280 | .reg_bits = 8, |
281 | .val_bits = 8, |
282 | .max_register = 0x1D, |
283 | }; |
284 | |
285 | static int ltc2991_init(struct ltc2991_state *st, struct device *dev) |
286 | { |
287 | struct fwnode_handle *child; |
288 | int ret; |
289 | u32 val, addr; |
290 | u8 v5_v8_reg_data = 0, v1_v4_reg_data = 0; |
291 | |
292 | ret = devm_regulator_get_enable(dev, id: "vcc" ); |
293 | if (ret) |
294 | return dev_err_probe(dev, err: ret, |
295 | fmt: "failed to enable regulator\n" ); |
296 | |
297 | device_for_each_child_node(dev, child) { |
298 | ret = fwnode_property_read_u32(fwnode: child, propname: "reg" , val: &addr); |
299 | if (ret < 0) { |
300 | fwnode_handle_put(fwnode: child); |
301 | return ret; |
302 | } |
303 | |
304 | if (addr > 3) { |
305 | fwnode_handle_put(fwnode: child); |
306 | return -EINVAL; |
307 | } |
308 | |
309 | ret = fwnode_property_read_u32(fwnode: child, |
310 | propname: "shunt-resistor-micro-ohms" , |
311 | val: &val); |
312 | if (!ret) { |
313 | if (!val) |
314 | return dev_err_probe(dev, err: -EINVAL, |
315 | fmt: "shunt resistor value cannot be zero\n" ); |
316 | |
317 | st->r_sense_uohm[addr] = val; |
318 | |
319 | switch (addr) { |
320 | case 0: |
321 | v1_v4_reg_data |= LTC2991_V1_V2_DIFF_EN; |
322 | break; |
323 | case 1: |
324 | v1_v4_reg_data |= LTC2991_V3_V4_DIFF_EN; |
325 | break; |
326 | case 2: |
327 | v5_v8_reg_data |= LTC2991_V5_V6_DIFF_EN; |
328 | break; |
329 | case 3: |
330 | v5_v8_reg_data |= LTC2991_V7_V8_DIFF_EN; |
331 | break; |
332 | default: |
333 | break; |
334 | } |
335 | } |
336 | |
337 | ret = fwnode_property_read_bool(fwnode: child, |
338 | propname: "adi,temperature-enable" ); |
339 | if (ret) { |
340 | st->temp_en[addr] = ret; |
341 | |
342 | switch (addr) { |
343 | case 0: |
344 | v1_v4_reg_data |= LTC2991_V1_V2_TEMP_EN; |
345 | break; |
346 | case 1: |
347 | v1_v4_reg_data |= LTC2991_V3_V4_TEMP_EN; |
348 | break; |
349 | case 2: |
350 | v5_v8_reg_data |= LTC2991_V5_V6_TEMP_EN; |
351 | break; |
352 | case 3: |
353 | v5_v8_reg_data |= LTC2991_V7_V8_TEMP_EN; |
354 | break; |
355 | default: |
356 | break; |
357 | } |
358 | } |
359 | } |
360 | |
361 | ret = regmap_write(map: st->regmap, LTC2991_V5_V8_CTRL, val: v5_v8_reg_data); |
362 | if (ret) |
363 | return dev_err_probe(dev, err: ret, |
364 | fmt: "Error: Failed to set V5-V8 CTRL reg.\n" ); |
365 | |
366 | ret = regmap_write(map: st->regmap, LTC2991_V1_V4_CTRL, val: v1_v4_reg_data); |
367 | if (ret) |
368 | return dev_err_probe(dev, err: ret, |
369 | fmt: "Error: Failed to set V1-V4 CTRL reg.\n" ); |
370 | |
371 | ret = regmap_write(map: st->regmap, LTC2991_PWM_TH_LSB_T_INT, |
372 | LTC2991_REPEAT_ACQ_EN); |
373 | if (ret) |
374 | return dev_err_probe(dev, err: ret, |
375 | fmt: "Error: Failed to set continuous mode.\n" ); |
376 | |
377 | /* Enable all channels and trigger conversions */ |
378 | return regmap_write(map: st->regmap, LTC2991_CH_EN_TRIGGER, |
379 | LTC2991_V7_V8_EN | LTC2991_V5_V6_EN | |
380 | LTC2991_V3_V4_EN | LTC2991_V1_V2_EN | |
381 | LTC2991_T_INT_VCC_EN); |
382 | } |
383 | |
384 | static int ltc2991_i2c_probe(struct i2c_client *client) |
385 | { |
386 | int ret; |
387 | struct device *hwmon_dev; |
388 | struct ltc2991_state *st; |
389 | |
390 | st = devm_kzalloc(dev: &client->dev, size: sizeof(*st), GFP_KERNEL); |
391 | if (!st) |
392 | return -ENOMEM; |
393 | |
394 | st->regmap = devm_regmap_init_i2c(client, <c2991_regmap_config); |
395 | if (IS_ERR(ptr: st->regmap)) |
396 | return PTR_ERR(ptr: st->regmap); |
397 | |
398 | ret = ltc2991_init(st, dev: &client->dev); |
399 | if (ret) |
400 | return ret; |
401 | |
402 | hwmon_dev = devm_hwmon_device_register_with_info(dev: &client->dev, |
403 | name: client->name, drvdata: st, |
404 | info: <c2991_chip_info, |
405 | NULL); |
406 | |
407 | return PTR_ERR_OR_ZERO(ptr: hwmon_dev); |
408 | } |
409 | |
410 | static const struct of_device_id ltc2991_of_match[] = { |
411 | { .compatible = "adi,ltc2991" }, |
412 | { } |
413 | }; |
414 | MODULE_DEVICE_TABLE(of, ltc2991_of_match); |
415 | |
416 | static const struct i2c_device_id ltc2991_i2c_id[] = { |
417 | { "ltc2991" , 0 }, |
418 | {} |
419 | }; |
420 | MODULE_DEVICE_TABLE(i2c, ltc2991_i2c_id); |
421 | |
422 | static struct i2c_driver ltc2991_i2c_driver = { |
423 | .driver = { |
424 | .name = "ltc2991" , |
425 | .of_match_table = ltc2991_of_match, |
426 | }, |
427 | .probe = ltc2991_i2c_probe, |
428 | .id_table = ltc2991_i2c_id, |
429 | }; |
430 | |
431 | module_i2c_driver(ltc2991_i2c_driver); |
432 | |
433 | MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>" ); |
434 | MODULE_DESCRIPTION("Analog Devices LTC2991 HWMON Driver" ); |
435 | MODULE_LICENSE("GPL" ); |
436 | |