1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2023 Carl Zeiss Meditec AG
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT adi_adltc2990
8 
9 #include <zephyr/sys/util.h>
10 #include <zephyr/drivers/i2c.h>
11 
12 #include "adltc2990_reg.h"
13 #include "adltc2990.h"
14 
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(adltc2990, CONFIG_SENSOR_LOG_LEVEL);
17 
adltc2990_get_v1_v2_measurement_modes(uint8_t mode_4_3,uint8_t mode_2_0)18 static enum adltc2990_monitoring_type adltc2990_get_v1_v2_measurement_modes(uint8_t mode_4_3,
19 									    uint8_t mode_2_0)
20 {
21 	if (mode_2_0 > ADLTC2990_MODE_2_0_MAX_VALUE || mode_4_3 > ADLTC2990_MODE_4_3_MAX_VALUE) {
22 		LOG_ERR("Invalid Measurement Mode");
23 		return -EINVAL;
24 	}
25 	if (mode_4_3 == ADLTC2990_MEASURE_INTERNAL_TEMPERATURE_ONLY ||
26 	    mode_4_3 == ADLTC2990_MEASURE_PINS_V3_V4_ONLY) {
27 		return NOTHING;
28 	}
29 
30 	enum adltc2990_monitoring_type type = NOTHING;
31 
32 	switch (mode_2_0) {
33 	case ADLTC2990_MODE_V1_V2_TR2:
34 	case ADLTC2990_MODE_V1_V2_V3_V4: {
35 		type = VOLTAGE_SINGLEENDED;
36 		break;
37 	}
38 	case ADLTC2990_MODE_V1_MINUS_V2_TR2:
39 	case ADLTC2990_MODE_V1_MINUS_V2_V3_V4:
40 	case ADLTC2990_MODE_V1_MINUS_V2_V3_MINUS_V4: {
41 		type = VOLTAGE_DIFFERENTIAL;
42 		break;
43 	}
44 	case ADLTC2990_MODE_TR1_V3_V4:
45 	case ADLTC2990_MODE_TR1_V3_MINUS_V4: {
46 	case ADLTC2990_MODE_TR1_TR2:
47 		type = TEMPERATURE;
48 		break;
49 	}
50 	default: {
51 		break;
52 	}
53 	}
54 	return type;
55 }
56 
adltc2990_get_v3_v4_measurement_modes(uint8_t mode_4_3,uint8_t mode_2_0)57 static enum adltc2990_monitoring_type adltc2990_get_v3_v4_measurement_modes(uint8_t mode_4_3,
58 									    uint8_t mode_2_0)
59 {
60 	if (mode_2_0 > ADLTC2990_MODE_2_0_MAX_VALUE || mode_4_3 > ADLTC2990_MODE_4_3_MAX_VALUE) {
61 		LOG_ERR("Invalid Measurement Mode");
62 		return -EINVAL;
63 	}
64 	if (mode_4_3 == ADLTC2990_MEASURE_INTERNAL_TEMPERATURE_ONLY ||
65 	    mode_4_3 == ADLTC2990_MEASURE_PINS_V1_V2_ONLY) {
66 		return NOTHING;
67 	}
68 
69 	enum adltc2990_monitoring_type type = NOTHING;
70 
71 	switch (mode_2_0) {
72 	case ADLTC2990_MODE_V1_V2_TR2:
73 	case ADLTC2990_MODE_V1_MINUS_V2_TR2:
74 	case ADLTC2990_MODE_TR1_TR2: {
75 		type = TEMPERATURE;
76 		break;
77 	}
78 
79 	case ADLTC2990_MODE_V1_MINUS_V2_V3_V4:
80 	case ADLTC2990_MODE_TR1_V3_V4:
81 	case ADLTC2990_MODE_V1_V2_V3_V4: {
82 		type = VOLTAGE_SINGLEENDED;
83 		break;
84 	}
85 	case ADLTC2990_MODE_TR1_V3_MINUS_V4:
86 	case ADLTC2990_MODE_V1_MINUS_V2_V3_MINUS_V4: {
87 		type = VOLTAGE_DIFFERENTIAL;
88 		break;
89 	}
90 	default: {
91 		break;
92 	}
93 	}
94 	return type;
95 }
96 
adltc2990_is_busy(const struct device * dev)97 static bool adltc2990_is_busy(const struct device *dev)
98 {
99 	const struct adltc2990_config *cfg = dev->config;
100 	uint8_t status_reg = 0;
101 
102 	i2c_reg_read_byte_dt(&cfg->bus, ADLTC2990_REG_STATUS, &status_reg);
103 	return status_reg & BIT(0);
104 }
105 
adltc2990_get_v1_v2_val(const struct device * dev,struct sensor_value * val,uint8_t num_values,uint8_t * const offset_index)106 static void adltc2990_get_v1_v2_val(const struct device *dev, struct sensor_value *val,
107 				    uint8_t num_values, uint8_t *const offset_index)
108 {
109 	struct adltc2990_data *data = dev->data;
110 
111 	for (uint8_t index = 0; index < num_values; index++) {
112 		val[index].val1 = data->pins_v1_v2_values[index] / 1000000;
113 		val[index].val2 = data->pins_v1_v2_values[index] % 1000000;
114 		*offset_index = index + 1;
115 	}
116 }
117 
adltc2990_get_v3_v4_val(const struct device * dev,struct sensor_value * val,uint8_t num_values,uint8_t const * const offset)118 static void adltc2990_get_v3_v4_val(const struct device *dev, struct sensor_value *val,
119 				    uint8_t num_values, uint8_t const *const offset)
120 {
121 	struct adltc2990_data *data = dev->data;
122 
123 	uint8_t offset_index = *offset;
124 
125 	for (uint8_t index = 0; index < num_values; index++) {
126 		val[index + offset_index].val1 = data->pins_v3_v4_values[index] / 1000000;
127 		val[index + offset_index].val2 = data->pins_v3_v4_values[index] % 1000000;
128 	}
129 }
130 
adltc2990_trigger_measurement(const struct device * dev)131 static int adltc2990_trigger_measurement(const struct device *dev)
132 {
133 	const struct adltc2990_config *cfg = dev->config;
134 
135 	return i2c_reg_write_byte_dt(&cfg->bus, ADLTC2990_REG_TRIGGER, 0x1);
136 }
137 
adltc2990_get_property_value(const struct device * dev,enum adltc2990_monitoring_type type,enum adltc2990_monitor_pins pin)138 static int32_t adltc2990_get_property_value(const struct device *dev,
139 					    enum adltc2990_monitoring_type type,
140 					    enum adltc2990_monitor_pins pin)
141 {
142 	const struct adltc2990_config *cfg = dev->config;
143 
144 	uint8_t msb_value = 0, lsb_value = 0;
145 	uint8_t msb_address, lsb_address;
146 
147 	switch (pin) {
148 	case V1: {
149 		msb_address = ADLTC2990_REG_V1_MSB;
150 		lsb_address = ADLTC2990_REG_V1_LSB;
151 		break;
152 	}
153 	case V2: {
154 		msb_address = ADLTC2990_REG_V2_MSB;
155 		lsb_address = ADLTC2990_REG_V2_LSB;
156 		break;
157 	}
158 	case V3: {
159 		msb_address = ADLTC2990_REG_V3_MSB;
160 		lsb_address = ADLTC2990_REG_V3_LSB;
161 		break;
162 	}
163 	case V4: {
164 		msb_address = ADLTC2990_REG_V4_MSB;
165 		lsb_address = ADLTC2990_REG_V4_LSB;
166 		break;
167 	}
168 	case INTERNAL_TEMPERATURE: {
169 		msb_address = ADLTC2990_REG_INTERNAL_TEMP_MSB;
170 		lsb_address = ADLTC2990_REG_INTERNAL_TEMP_LSB;
171 		break;
172 	}
173 	case SUPPLY_VOLTAGE: {
174 		msb_address = ADLTC2990_REG_VCC_MSB;
175 		lsb_address = ADLTC2990_REG_VCC_LSB;
176 		break;
177 	}
178 	default: {
179 		LOG_ERR("Trying to access illegal register");
180 		return -EINVAL;
181 	}
182 	}
183 
184 	i2c_reg_read_byte_dt(&cfg->bus, msb_address, &msb_value);
185 	i2c_reg_read_byte_dt(&cfg->bus, lsb_address, &lsb_value);
186 	uint16_t conversion_factor;
187 	uint8_t negative_bit_index;
188 
189 	if (type == VOLTAGE_SINGLEENDED) {
190 		conversion_factor = ADLTC2990_VOLTAGE_SINGLEENDED_CONVERSION_FACTOR;
191 		negative_bit_index = 14;
192 	} else if (type == VOLTAGE_DIFFERENTIAL) {
193 		conversion_factor = ADLTC2990_VOLTAGE_DIFFERENTIAL_CONVERSION_FACTOR;
194 		negative_bit_index = 14;
195 	} else if (type == TEMPERATURE) {
196 		conversion_factor = ADLTC2990_TEMPERATURE_CONVERSION_FACTOR;
197 		negative_bit_index = 12;
198 	} else {
199 		LOG_ERR("unknown type");
200 		return -EINVAL;
201 	}
202 
203 	int16_t value = (msb_value<<8)+lsb_value;
204 
205 	int32_t voltage_value = (value << (31-negative_bit_index))>>(31-negative_bit_index);
206 
207 	return (voltage_value * conversion_factor) / 100;
208 }
209 
adltc2990_init(const struct device * dev)210 static int adltc2990_init(const struct device *dev)
211 {
212 	const struct adltc2990_config *cfg = dev->config;
213 
214 	if (!i2c_is_ready_dt(&cfg->bus)) {
215 		LOG_ERR("I2C bus %s not ready", cfg->bus.bus->name);
216 		return -ENODEV;
217 	}
218 
219 	const uint8_t ctrl_reg_setting = cfg->temp_format << 7 | cfg->acq_format << 6 | 0 << 5 |
220 					 cfg->measurement_mode[1] << 3 | cfg->measurement_mode[0];
221 
222 	LOG_DBG("Setting Control Register to: 0x%x", ctrl_reg_setting);
223 	int err = i2c_reg_write_byte_dt(&cfg->bus, ADLTC2990_REG_CONTROL, ctrl_reg_setting);
224 
225 	if (err < 0) {
226 		LOG_ERR("configuring for single bus failed: %d", err);
227 		return err;
228 	}
229 	LOG_INF("Initializing ADLTC2990 with name %s", dev->name);
230 	return 0;
231 }
232 
adltc2990_sample_fetch(const struct device * dev,enum sensor_channel chan)233 static int adltc2990_sample_fetch(const struct device *dev, enum sensor_channel chan)
234 {
235 	struct adltc2990_data *data = dev->data;
236 	const struct adltc2990_config *cfg = dev->config;
237 	enum adltc2990_monitoring_type mode_v1_v2 = adltc2990_get_v1_v2_measurement_modes(
238 		cfg->measurement_mode[1], cfg->measurement_mode[0]);
239 	enum adltc2990_monitoring_type mode_v3_v4 = adltc2990_get_v3_v4_measurement_modes(
240 		cfg->measurement_mode[1], cfg->measurement_mode[0]);
241 
242 	float voltage_divider_ratio;
243 
244 	switch (chan) {
245 	case SENSOR_CHAN_DIE_TEMP: {
246 		data->internal_temperature =
247 			adltc2990_get_property_value(dev, TEMPERATURE, INTERNAL_TEMPERATURE);
248 		break;
249 	}
250 	case SENSOR_CHAN_CURRENT: {
251 		if (!(mode_v1_v2 == VOLTAGE_DIFFERENTIAL || mode_v3_v4 == VOLTAGE_DIFFERENTIAL)) {
252 			LOG_ERR("Sensor is not configured to measure Current");
253 			return -EINVAL;
254 		}
255 		if (mode_v1_v2 == VOLTAGE_DIFFERENTIAL) {
256 			data->pins_v1_v2_values[0] =
257 				(adltc2990_get_property_value(dev, VOLTAGE_DIFFERENTIAL, V1) *
258 				 ADLTC2990_MICROOHM_CONVERSION_FACTOR) /
259 				cfg->pins_v1_v2.pins_current_resistor;
260 		}
261 		if (mode_v3_v4 == VOLTAGE_DIFFERENTIAL) {
262 			data->pins_v3_v4_values[0] =
263 				(adltc2990_get_property_value(dev, VOLTAGE_DIFFERENTIAL, V3) *
264 				 ADLTC2990_MICROOHM_CONVERSION_FACTOR) /
265 				cfg->pins_v3_v4.pins_current_resistor;
266 		}
267 		break;
268 	}
269 	case SENSOR_CHAN_VOLTAGE: {
270 		data->supply_voltage =
271 			adltc2990_get_property_value(dev, VOLTAGE_SINGLEENDED, SUPPLY_VOLTAGE) +
272 			2500000;
273 
274 		if (mode_v1_v2 == VOLTAGE_DIFFERENTIAL) {
275 			data->pins_v1_v2_values[0] =
276 				adltc2990_get_property_value(dev, VOLTAGE_DIFFERENTIAL, V1);
277 		} else if (mode_v1_v2 == VOLTAGE_SINGLEENDED) {
278 			uint32_t v1_r1 =
279 				cfg->pins_v1_v2.voltage_divider_resistors.v1_r1_r2[0];
280 			uint32_t v1_r2 =
281 				cfg->pins_v1_v2.voltage_divider_resistors.v2_r1_r2[1];
282 			voltage_divider_ratio = DIV_ROUND_CLOSEST(v1_r1 + v1_r2, v1_r2);
283 			data->pins_v1_v2_values[0] =
284 				adltc2990_get_property_value(dev, VOLTAGE_SINGLEENDED, V1) *
285 				voltage_divider_ratio;
286 
287 			uint32_t v2_r1 =
288 				cfg->pins_v1_v2.voltage_divider_resistors.v2_r1_r2[0];
289 			uint32_t v2_r2 =
290 				cfg->pins_v1_v2.voltage_divider_resistors.v2_r1_r2[1];
291 			voltage_divider_ratio = DIV_ROUND_CLOSEST(v2_r1 + v2_r2, v2_r2);
292 			data->pins_v1_v2_values[1] =
293 				adltc2990_get_property_value(dev, VOLTAGE_SINGLEENDED, V2) *
294 				voltage_divider_ratio;
295 		}
296 
297 		if (mode_v3_v4 == VOLTAGE_DIFFERENTIAL) {
298 			data->pins_v3_v4_values[0] =
299 				adltc2990_get_property_value(dev, VOLTAGE_DIFFERENTIAL, V3);
300 		} else if (mode_v3_v4 == VOLTAGE_SINGLEENDED) {
301 			uint32_t v3_r1 =
302 				cfg->pins_v3_v4.voltage_divider_resistors.v3_r1_r2[0];
303 			uint32_t v3_r2 =
304 				cfg->pins_v3_v4.voltage_divider_resistors.v3_r1_r2[1];
305 			voltage_divider_ratio = DIV_ROUND_CLOSEST(v3_r1 + v3_r2, v3_r2);
306 			data->pins_v3_v4_values[0] =
307 				adltc2990_get_property_value(dev, VOLTAGE_SINGLEENDED, V3) *
308 				voltage_divider_ratio;
309 
310 			uint32_t v4_r1 =
311 				cfg->pins_v3_v4.voltage_divider_resistors.v4_r1_r2[0];
312 			uint32_t v4_r2 =
313 				cfg->pins_v3_v4.voltage_divider_resistors.v4_r1_r2[1];
314 			voltage_divider_ratio = DIV_ROUND_CLOSEST((v4_r1 + v4_r2), v4_r2);
315 			data->pins_v3_v4_values[1] =
316 				adltc2990_get_property_value(dev, VOLTAGE_SINGLEENDED, V4) *
317 				voltage_divider_ratio;
318 		}
319 		break;
320 	}
321 	case SENSOR_CHAN_AMBIENT_TEMP: {
322 		if (!(mode_v1_v2 == TEMPERATURE || mode_v3_v4 == TEMPERATURE)) {
323 			LOG_ERR("Sensor is not configured to measure Ambient Temperature");
324 			return -EINVAL;
325 		}
326 		if (mode_v1_v2 == TEMPERATURE) {
327 			data->pins_v1_v2_values[0] =
328 				adltc2990_get_property_value(dev, TEMPERATURE, V1);
329 		}
330 		if (mode_v3_v4 == TEMPERATURE) {
331 			data->pins_v3_v4_values[1] =
332 				adltc2990_get_property_value(dev, TEMPERATURE, V3);
333 		}
334 		break;
335 	}
336 	case SENSOR_CHAN_ALL: {
337 		if (adltc2990_is_busy(dev)) {
338 			LOG_INF("ADLTC2990 conversion ongoing");
339 			return -EBUSY;
340 		}
341 		adltc2990_trigger_measurement(dev);
342 		break;
343 	}
344 	default: {
345 		LOG_ERR("does not measure channel: %d", chan);
346 		return -ENOTSUP;
347 	}
348 	}
349 
350 	return 0;
351 }
352 
adltc2990_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)353 static int adltc2990_channel_get(const struct device *dev, enum sensor_channel chan,
354 				 struct sensor_value *val)
355 {
356 	if (val == NULL) {
357 		LOG_ERR("Argument of type sensor_value* cannot be null ");
358 		return -EINVAL;
359 	}
360 	struct adltc2990_data *data = dev->data;
361 	const struct adltc2990_config *cfg = dev->config;
362 	enum adltc2990_monitoring_type mode_v1_v2 = adltc2990_get_v1_v2_measurement_modes(
363 		cfg->measurement_mode[1], cfg->measurement_mode[0]);
364 	enum adltc2990_monitoring_type mode_v3_v4 = adltc2990_get_v3_v4_measurement_modes(
365 		cfg->measurement_mode[1], cfg->measurement_mode[0]);
366 
367 	uint8_t offset_index = 0, num_values_v1_v2 = 0, num_values_v3_v4 = 0;
368 
369 	switch (chan) {
370 	case SENSOR_CHAN_DIE_TEMP: {
371 		val->val1 = data->internal_temperature / 10000;
372 		val->val2 = data->internal_temperature % 10000;
373 		LOG_DBG("Internal Temperature Value is:%d.%d", val->val1, val->val2);
374 		break;
375 	}
376 	case SENSOR_CHAN_VOLTAGE: {
377 		if (mode_v1_v2 == VOLTAGE_SINGLEENDED) {
378 			LOG_DBG("Getting V1,V2");
379 			num_values_v1_v2 = ADLTC2990_VOLTAGE_SINGLE_ENDED_VALUES;
380 		} else if (mode_v1_v2 == VOLTAGE_DIFFERENTIAL) {
381 			LOG_DBG("Getting V3-V4");
382 			num_values_v1_v2 = ADLTC2990_VOLTAGE_DIFF_VALUES;
383 		}
384 		if (mode_v3_v4 == VOLTAGE_SINGLEENDED) {
385 			LOG_DBG("Getting V3,V4");
386 			num_values_v3_v4 = ADLTC2990_VOLTAGE_SINGLE_ENDED_VALUES;
387 		} else if (mode_v3_v4 == VOLTAGE_DIFFERENTIAL) {
388 			LOG_DBG("Getting V3-V4");
389 			num_values_v3_v4 = ADLTC2990_VOLTAGE_DIFF_VALUES;
390 		}
391 		val[num_values_v1_v2 + num_values_v3_v4].val1 = data->supply_voltage / 1000000;
392 		val[num_values_v1_v2 + num_values_v3_v4].val2 = data->supply_voltage % 1000000;
393 		break;
394 	}
395 	case SENSOR_CHAN_CURRENT: {
396 		if (!(mode_v1_v2 == VOLTAGE_DIFFERENTIAL || mode_v3_v4 == VOLTAGE_DIFFERENTIAL)) {
397 			LOG_ERR("Sensor is not configured to measure Current");
398 			return -EINVAL;
399 		}
400 		if (mode_v1_v2 == VOLTAGE_DIFFERENTIAL && mode_v3_v4 == VOLTAGE_DIFFERENTIAL) {
401 			LOG_DBG("Getting I12 and I34");
402 			num_values_v1_v2 = ADLTC2990_CURRENT_VALUES;
403 			num_values_v3_v4 = ADLTC2990_CURRENT_VALUES;
404 		} else if (mode_v1_v2 == VOLTAGE_DIFFERENTIAL) {
405 			LOG_DBG("Getting I12");
406 			num_values_v1_v2 = ADLTC2990_CURRENT_VALUES;
407 		} else if (mode_v3_v4 == VOLTAGE_DIFFERENTIAL) {
408 			LOG_DBG("Getting I34");
409 			num_values_v3_v4 = ADLTC2990_CURRENT_VALUES;
410 		}
411 		break;
412 	}
413 	case SENSOR_CHAN_AMBIENT_TEMP: {
414 		if (!(mode_v1_v2 == TEMPERATURE || mode_v3_v4 == TEMPERATURE)) {
415 			LOG_ERR("Sensor is not configured to measure Ambient Temperature");
416 			return -EINVAL;
417 		}
418 		if (mode_v1_v2 == TEMPERATURE && mode_v3_v4 == TEMPERATURE) {
419 			LOG_DBG("Getting T12 and T34");
420 			num_values_v1_v2 = ADLTC2990_TEMP_VALUES;
421 			num_values_v3_v4 = ADLTC2990_TEMP_VALUES;
422 		} else if (mode_v1_v2 == TEMPERATURE) {
423 			LOG_DBG("Getting T12");
424 			num_values_v1_v2 = ADLTC2990_TEMP_VALUES;
425 		} else if (mode_v3_v4 == TEMPERATURE) {
426 			LOG_DBG("Getting T34");
427 			num_values_v3_v4 = ADLTC2990_TEMP_VALUES;
428 		}
429 		break;
430 	}
431 	default: {
432 		return -ENOTSUP;
433 	}
434 	}
435 
436 	adltc2990_get_v1_v2_val(dev, val, num_values_v1_v2, &offset_index);
437 	adltc2990_get_v3_v4_val(dev, val, num_values_v3_v4, &offset_index);
438 	return 0;
439 }
440 
441 static const struct sensor_driver_api adltc2990_driver_api = {
442 	.sample_fetch = adltc2990_sample_fetch,
443 	.channel_get = adltc2990_channel_get,
444 };
445 
446 #define ADLTC2990_DEFINE(inst)                                                                     \
447 	static struct adltc2990_data adltc2990_data_##inst;                                        \
448 	static const struct adltc2990_config adltc2990_config_##inst = {                           \
449 		.bus = I2C_DT_SPEC_INST_GET(inst),                                                 \
450 		.temp_format = DT_INST_PROP(inst, temperature_format),                             \
451 		.acq_format = DT_INST_PROP(inst, acquistion_format),                               \
452 		.measurement_mode = DT_INST_PROP(inst, measurement_mode),                          \
453 		.pins_v1_v2.pins_current_resistor =                                  \
454 			DT_INST_PROP_OR(inst, pins_v1_v2_current_resistor, 1),                     \
455 		.pins_v1_v2.voltage_divider_resistors.v1_r1_r2 =                     \
456 			DT_INST_PROP_OR(inst, pin_v1_voltage_divider_resistors, NULL),             \
457 		.pins_v1_v2.voltage_divider_resistors.v2_r1_r2 =                     \
458 			DT_INST_PROP_OR(inst, pin_v2_voltage_divider_resistors, NULL),             \
459 		.pins_v3_v4.pins_current_resistor =                                  \
460 			DT_INST_PROP_OR(inst, pins_v3_v4_current_resistor, 1),                     \
461 		.pins_v3_v4.voltage_divider_resistors.v3_r1_r2 =                     \
462 			DT_INST_PROP_OR(inst, pin_v3_voltage_divider_resistors, NULL),             \
463 		.pins_v3_v4.voltage_divider_resistors.v4_r1_r2 =                     \
464 			DT_INST_PROP_OR(inst, pin_v4_voltage_divider_resistors, NULL)};            \
465                                                                                                    \
466 	SENSOR_DEVICE_DT_INST_DEFINE(inst, adltc2990_init, NULL, &adltc2990_data_##inst,           \
467 				     &adltc2990_config_##inst, POST_KERNEL,                        \
468 				     CONFIG_SENSOR_INIT_PRIORITY, &adltc2990_driver_api);
469 
470 DT_INST_FOREACH_STATUS_OKAY(ADLTC2990_DEFINE)
471