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
56struct ltc2991_state {
57 struct regmap *regmap;
58 u32 r_sense_uohm[LTC2991_MAX_CHANNEL];
59 bool temp_en[LTC2991_MAX_CHANNEL];
60};
61
62static 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: &regvals, val_count: reg_len);
72 if (ret)
73 return ret;
74
75 *val = be16_to_cpu(regvals);
76
77 return 0;
78}
79
80static 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: &reg_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
99static 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
117static 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: &reg_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
133static 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
148static 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: &reg_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
163static 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
182static 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
197static 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
241static const struct hwmon_ops ltc2991_hwmon_ops = {
242 .is_visible = ltc2991_is_visible,
243 .read = ltc2991_read,
244};
245
246static 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
274static const struct hwmon_chip_info ltc2991_chip_info = {
275 .ops = &ltc2991_hwmon_ops,
276 .info = ltc2991_info,
277};
278
279static const struct regmap_config ltc2991_regmap_config = {
280 .reg_bits = 8,
281 .val_bits = 8,
282 .max_register = 0x1D,
283};
284
285static 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
384static 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, &ltc2991_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: &ltc2991_chip_info,
405 NULL);
406
407 return PTR_ERR_OR_ZERO(ptr: hwmon_dev);
408}
409
410static const struct of_device_id ltc2991_of_match[] = {
411 { .compatible = "adi,ltc2991" },
412 { }
413};
414MODULE_DEVICE_TABLE(of, ltc2991_of_match);
415
416static const struct i2c_device_id ltc2991_i2c_id[] = {
417 { "ltc2991", 0 },
418 {}
419};
420MODULE_DEVICE_TABLE(i2c, ltc2991_i2c_id);
421
422static 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
431module_i2c_driver(ltc2991_i2c_driver);
432
433MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
434MODULE_DESCRIPTION("Analog Devices LTC2991 HWMON Driver");
435MODULE_LICENSE("GPL");
436

source code of linux/drivers/hwmon/ltc2991.c