1 /*
2 * Copyright (c) 2024 Florian Weber <Florian.Weber@live.de>
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #define DT_DRV_COMPAT melexis_mlx90394
7
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/i2c.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/drivers/sensor_data_types.h>
13 #include <zephyr/sys/__assert.h>
14 #include <zephyr/sys/byteorder.h>
15 #include <zephyr/sys/util.h>
16 #include <zephyr/logging/log.h>
17 #include <zephyr/drivers/sensor/mlx90394.h>
18
19 #include "mlx90394.h"
20 #include "mlx90394_reg.h"
21
22 LOG_MODULE_REGISTER(MLX90394, CONFIG_SENSOR_LOG_LEVEL);
23
24 /*
25 * conversion time of one single axis for different filter orders if osr is enabled the value has
26 * to be doubled
27 */
28 static const int32_t MLX90394_CONVERSION_TIME_US_AXIS[] = {111, 170, 270, 490,
29 910, 1770, 3470, 6890};
30
31 /* conversion time per axis dependent of filter order */
32
33 /*
34 * DSP Time per measurement first index:temperature sensor count ( 0..1 ) second index:
35 * magnetic axis count (0..3) in us
36 */
37 static const int32_t MLX90394_DSP_TIME_US[2][4] = {{0, 27, 50, 73}, {20, 63, 86, 110}};
38
mlx90394_update_measurement_Time_us(struct mlx90394_data * data)39 static void mlx90394_update_measurement_Time_us(struct mlx90394_data *data)
40 {
41 int32_t en_x = FIELD_GET(MLX90394_CTRL1_X_EN, data->ctrl_reg_values.ctrl1);
42 int32_t en_y = FIELD_GET(MLX90394_CTRL1_Y_EN, data->ctrl_reg_values.ctrl1);
43 int32_t en_z = FIELD_GET(MLX90394_CTRL1_Z_EN, data->ctrl_reg_values.ctrl1);
44 int32_t en_temp = FIELD_GET(MLX90394_CTRL4_T_EN, data->ctrl_reg_values.ctrl4);
45 int32_t filter_hall_xy =
46 FIELD_GET(MLX90394_CTRL3_DIG_FILT_HALL_XY, data->ctrl_reg_values.ctrl3);
47 int32_t filter_hall_z =
48 FIELD_GET(MLX90394_CTRL4_DIG_FILT_HALL_Z, data->ctrl_reg_values.ctrl4);
49 int32_t filter_temp = FIELD_GET(MLX90394_CTRL3_DIG_FILT_TEMP, data->ctrl_reg_values.ctrl3);
50 int32_t osr_temp = FIELD_GET(MLX90394_CTRL3_OSR_TEMP, data->ctrl_reg_values.ctrl3);
51 int32_t osr_hall = FIELD_GET(MLX90394_CTRL3_OSR_HALL, data->ctrl_reg_values.ctrl3);
52
53 int32_t conversion_time_us =
54 (osr_hall + 1) * ((en_x + en_y) * MLX90394_CONVERSION_TIME_US_AXIS[filter_hall_xy] +
55 en_z * MLX90394_CONVERSION_TIME_US_AXIS[filter_hall_z]) +
56 (osr_temp + 1) * en_temp * MLX90394_CONVERSION_TIME_US_AXIS[filter_temp];
57 int32_t dsp_time_us = MLX90394_DSP_TIME_US[en_temp][en_x + en_y + en_z];
58
59 /*
60 * adding 5% tolerance from datasheet
61 */
62 data->measurement_time_us = (conversion_time_us + dsp_time_us) * 105 / 100;
63 }
64
mlx90394_convert_magn(enum mlx90394_reg_config_val config,struct sensor_value * val,uint8_t sample_l,uint8_t sample_h)65 static void mlx90394_convert_magn(enum mlx90394_reg_config_val config, struct sensor_value *val,
66 uint8_t sample_l, uint8_t sample_h)
67 {
68 int64_t scale, conv_val;
69
70 if (config == MLX90394_CTRL2_CONFIG_HIGH_SENSITIVITY_LOW_NOISE) {
71 scale = MLX90394_HIGH_SENSITIVITY_MICRO_GAUSS_PER_BIT;
72 } else {
73 scale = MLX90394_HIGH_RANGE_MICRO_GAUSS_PER_BIT;
74 }
75 conv_val = (int16_t)((uint16_t)sample_l | (uint16_t)(sample_h << 8)) * scale;
76
77 val->val1 = conv_val / 1000000; /* G */
78 val->val2 = conv_val - (val->val1 * 1000000); /* uG */
79 }
80
mlx90394_convert_temp(struct sensor_value * val,uint8_t sample_l,uint8_t sample_h)81 static void mlx90394_convert_temp(struct sensor_value *val, uint8_t sample_l, uint8_t sample_h)
82 {
83 int64_t conv_val = sample_l | (sample_h << 8) * MLX90394_MICRO_CELSIUS_PER_BIT;
84
85 val->val1 = conv_val / 1000000; /* C */
86 val->val2 = (conv_val - (val->val1 * 1000000)); /* uC */
87 }
88
89 /*
90 * The user has to take care about that the requested channel was fetched before. Else the data will
91 * be random. Magnetic Flux Density is in Gauss, Temperature in Celsius
92 */
mlx90394_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)93 static int mlx90394_channel_get(const struct device *dev, enum sensor_channel chan,
94 struct sensor_value *val)
95 {
96 struct mlx90394_data *data = dev->data;
97
98 switch (chan) {
99 case SENSOR_CHAN_MAGN_X: {
100 mlx90394_convert_magn(data->config_val, val, data->sample.x_l, data->sample.x_h);
101 } break;
102 case SENSOR_CHAN_MAGN_Y: {
103 mlx90394_convert_magn(data->config_val, val, data->sample.y_l, data->sample.y_h);
104 } break;
105 case SENSOR_CHAN_MAGN_Z: {
106 mlx90394_convert_magn(data->config_val, val, data->sample.z_l, data->sample.z_h);
107 } break;
108 case SENSOR_CHAN_AMBIENT_TEMP: {
109 mlx90394_convert_temp(val, data->sample.temp_l, data->sample.temp_h);
110 } break;
111 case SENSOR_CHAN_MAGN_XYZ: {
112 mlx90394_convert_magn(data->config_val, val, data->sample.x_l, data->sample.x_h);
113 mlx90394_convert_magn(data->config_val, val + 1, data->sample.y_l,
114 data->sample.y_h);
115 mlx90394_convert_magn(data->config_val, val + 2, data->sample.z_l,
116 data->sample.z_h);
117 } break;
118 case SENSOR_CHAN_ALL: {
119 mlx90394_convert_magn(data->config_val, val, data->sample.x_l, data->sample.x_h);
120 mlx90394_convert_magn(data->config_val, val + 1, data->sample.y_l,
121 data->sample.y_h);
122 mlx90394_convert_magn(data->config_val, val + 2, data->sample.z_l,
123 data->sample.z_h);
124 mlx90394_convert_temp(val + 3, data->sample.temp_l, data->sample.temp_h);
125 } break;
126 default: {
127 LOG_DBG("Invalid channel %d", chan);
128 return -ENOTSUP;
129 }
130 }
131 return 0;
132 }
133
134 /**
135 * update a register on the device and @param old_value as well
136 */
mlx90394_update_register(const struct device * dev,const uint8_t reg_addr,const uint8_t new_val,uint8_t * old_value)137 static inline int mlx90394_update_register(const struct device *dev, const uint8_t reg_addr,
138 const uint8_t new_val, uint8_t *old_value)
139 {
140 const struct mlx90394_config *cfg = dev->config;
141
142 if (new_val != *old_value) {
143 *old_value = new_val;
144 return i2c_reg_write_byte_dt(&cfg->i2c, reg_addr, new_val);
145 }
146 return 0;
147 }
148
mlx90394_sync_config_val(const struct device * dev)149 static inline int mlx90394_sync_config_val(const struct device *dev)
150 {
151 struct mlx90394_data *data = dev->data;
152 uint8_t updated_ctrl2;
153
154 updated_ctrl2 = MLX90394_FIELD_MOD(MLX90394_CTRL2_CONFIG, data->config_val,
155 data->ctrl_reg_values.ctrl2);
156
157 return mlx90394_update_register(dev, MLX90394_REG_CTRL2, updated_ctrl2,
158 &data->ctrl_reg_values.ctrl2);
159 }
160
mlx90394_fs_set(const struct device * dev,const struct sensor_value * val)161 static inline int mlx90394_fs_set(const struct device *dev, const struct sensor_value *val)
162 {
163 struct mlx90394_data *data = dev->data;
164
165 /*
166 * in low current mode, only High Range is possible
167 */
168 if (data->config_val == MLX90394_CTRL2_CONFIG_HIGH_RANGE_LOW_CURRENT) {
169 LOG_ERR("different FS values only supported in low noise mode");
170
171 return -ENOTSUP;
172 }
173
174 /* if the requested range is greater the driver switches from HIGH_SENSITIVITY to
175 * HIGH_RANGE
176 */
177 if (val->val1 > MLX90394_ATTR_FS_LOW_G) {
178 data->config_val = MLX90394_CTRL2_CONFIG_HIGH_RANGE_LOW_NOISE;
179 } else {
180 data->config_val = MLX90394_CTRL2_CONFIG_HIGH_SENSITIVITY_LOW_NOISE;
181 }
182
183 return mlx90394_sync_config_val(dev);
184 }
185
mlx90394_fs_get(const struct device * dev,struct sensor_value * val)186 static inline int mlx90394_fs_get(const struct device *dev, struct sensor_value *val)
187 {
188 struct mlx90394_data *data = dev->data;
189
190 val->val2 = 0;
191 if (data->config_val == MLX90394_CTRL2_CONFIG_HIGH_SENSITIVITY_LOW_NOISE) {
192 val->val1 = MLX90394_ATTR_FS_LOW_G;
193 } else {
194 val->val1 = MLX90394_ATTR_FS_HIGH_G;
195 }
196
197 return 0;
198 }
199
mlx90394_low_noise_set(const struct device * dev,struct sensor_value * val)200 static inline int mlx90394_low_noise_set(const struct device *dev, struct sensor_value *val)
201 {
202 struct mlx90394_data *data = dev->data;
203
204 switch (data->config_val) {
205 case MLX90394_CTRL2_CONFIG_HIGH_RANGE_LOW_CURRENT: {
206 if (val->val1) {
207 data->config_val = MLX90394_CTRL2_CONFIG_HIGH_RANGE_LOW_NOISE;
208
209 return mlx90394_sync_config_val(dev);
210 }
211 } break;
212 case MLX90394_CTRL2_CONFIG_HIGH_RANGE_LOW_NOISE: {
213 if (val->val1 == 0) {
214 data->config_val = MLX90394_CTRL2_CONFIG_HIGH_RANGE_LOW_CURRENT;
215
216 return mlx90394_sync_config_val(dev);
217 }
218 } break;
219 case MLX90394_CTRL2_CONFIG_HIGH_SENSITIVITY_LOW_NOISE: {
220 if (val->val1 == 0) {
221 LOG_ERR("High Sensitivity only supported in Low-Noise config, therefore "
222 "changing now to Low-Current config is not possible");
223
224 return -ENOTSUP;
225 }
226 } break;
227 }
228
229 return 0;
230 }
231
mlx90394_low_noise_get(const struct device * dev,struct sensor_value * val)232 static inline int mlx90394_low_noise_get(const struct device *dev, struct sensor_value *val)
233 {
234 struct mlx90394_data *data = dev->data;
235
236 val->val2 = 0;
237 if (data->config_val == MLX90394_CTRL2_CONFIG_HIGH_RANGE_LOW_CURRENT) {
238 val->val1 = 0;
239 } else {
240 val->val1 = 1;
241 }
242
243 return 0;
244 }
245
246 /*
247 * helper function to get/set attributes if set is 0 it will be a get, otherwise is interpreted
248 * as set
249 */
mlx90394_attr_helper(const struct device * dev,enum sensor_channel chan,unsigned int attr,struct sensor_value * val,uint8_t set)250 static int mlx90394_attr_helper(const struct device *dev, enum sensor_channel chan,
251 unsigned int attr, struct sensor_value *val, uint8_t set)
252 {
253 struct mlx90394_data *data = dev->data;
254
255 if (!data->initialized) {
256 return -ENODEV;
257 }
258
259 switch (attr) {
260 case SENSOR_ATTR_FULL_SCALE: {
261 if (chan != SENSOR_CHAN_MAGN_XYZ) {
262 return -ENOTSUP;
263 }
264
265 if (set) {
266 return mlx90394_fs_set(dev, val);
267 } else {
268 return mlx90394_fs_get(dev, val);
269 }
270 } break;
271
272 case MLX90394_SENSOR_ATTR_MAGN_LOW_NOISE: {
273 if (chan != SENSOR_CHAN_MAGN_XYZ) {
274 return -ENOTSUP;
275 }
276
277 if (set) {
278 return mlx90394_low_noise_set(dev, val);
279 } else {
280 return mlx90394_low_noise_get(dev, val);
281 }
282 } break;
283
284 case MLX90394_SENSOR_ATTR_MAGN_FILTER_XY: {
285 if (set) {
286 if (val->val1 > 7 || val->val1 < 0) {
287 return -EINVAL;
288 }
289
290 return mlx90394_update_register(
291 dev, MLX90394_REG_CTRL3,
292 MLX90394_FIELD_MOD(MLX90394_CTRL3_DIG_FILT_HALL_XY, val->val1,
293 data->ctrl_reg_values.ctrl3),
294 &data->ctrl_reg_values.ctrl3);
295 } else {
296 val->val1 = FIELD_GET(MLX90394_CTRL3_DIG_FILT_HALL_XY,
297 data->ctrl_reg_values.ctrl3);
298 val->val2 = 0;
299 }
300 } break;
301 case MLX90394_SENSOR_ATTR_MAGN_FILTER_Z: {
302 if (set) {
303 if (val->val1 > 7 || val->val1 < 0) {
304
305 return -EINVAL;
306 }
307
308 return mlx90394_update_register(
309 dev, MLX90394_REG_CTRL4,
310 MLX90394_FIELD_MOD(MLX90394_CTRL4_DIG_FILT_HALL_Z, val->val1,
311 data->ctrl_reg_values.ctrl4),
312 &data->ctrl_reg_values.ctrl4);
313 } else {
314 val->val1 = FIELD_GET(MLX90394_CTRL4_DIG_FILT_HALL_Z,
315 data->ctrl_reg_values.ctrl4);
316 val->val2 = 0;
317 }
318 } break;
319 case MLX90394_SENSOR_ATTR_MAGN_OSR: {
320 if (set) {
321 if (val->val1 > 1 || val->val1 < 0) {
322
323 return -EINVAL;
324 }
325
326 return mlx90394_update_register(
327 dev, MLX90394_REG_CTRL3,
328 MLX90394_FIELD_MOD(MLX90394_CTRL3_OSR_HALL, val->val1,
329 data->ctrl_reg_values.ctrl3),
330 &data->ctrl_reg_values.ctrl3);
331 } else {
332 val->val1 = FIELD_GET(MLX90394_CTRL3_OSR_HALL, data->ctrl_reg_values.ctrl3);
333 val->val2 = 0;
334 }
335 } break;
336 case MLX90394_SENSOR_ATTR_TEMP_FILTER: {
337 if (set) {
338 if (val->val1 > 7 || val->val1 < 0) {
339 return -EINVAL;
340 }
341 return mlx90394_update_register(
342 dev, MLX90394_REG_CTRL3,
343 MLX90394_FIELD_MOD(MLX90394_CTRL3_DIG_FILT_TEMP, val->val1,
344 data->ctrl_reg_values.ctrl3),
345 &data->ctrl_reg_values.ctrl3);
346 } else {
347 val->val1 = FIELD_GET(MLX90394_CTRL3_DIG_FILT_TEMP,
348 data->ctrl_reg_values.ctrl3);
349 val->val2 = 0;
350 }
351 } break;
352 case MLX90394_SENSOR_ATTR_TEMP_OSR: {
353 if (set) {
354 if (val->val1 > 1 || val->val1 < 0) {
355 return -EINVAL;
356 }
357 return mlx90394_update_register(
358 dev, MLX90394_REG_CTRL3,
359 MLX90394_FIELD_MOD(MLX90394_CTRL3_OSR_TEMP, val->val1,
360 data->ctrl_reg_values.ctrl3),
361 &data->ctrl_reg_values.ctrl3);
362 } else {
363 val->val1 = FIELD_GET(MLX90394_CTRL3_OSR_TEMP, data->ctrl_reg_values.ctrl3);
364 val->val2 = 0;
365 }
366 } break;
367 default: {
368 return -ENOTSUP;
369 }
370 }
371
372 return 0;
373 }
mlx90394_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)374 static int mlx90394_attr_get(const struct device *dev, enum sensor_channel chan,
375 enum sensor_attribute attr, struct sensor_value *val)
376 {
377 return mlx90394_attr_helper(dev, chan, (unsigned int)attr, val, 0);
378 }
379
mlx90394_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)380 static int mlx90394_attr_set(const struct device *dev, enum sensor_channel chan,
381 enum sensor_attribute attr, const struct sensor_value *val)
382 {
383 /*
384 * must be a copy because val is const
385 */
386 struct sensor_value val_copy = *val;
387 int rc;
388
389 rc = mlx90394_attr_helper(dev, chan, (unsigned int)attr, &val_copy, 1);
390 if (rc == 0) {
391 mlx90394_update_measurement_Time_us(dev->data);
392 }
393
394 return rc;
395 }
396
mlx90394_check_who_am_i(const struct i2c_dt_spec * i2c)397 static inline int mlx90394_check_who_am_i(const struct i2c_dt_spec *i2c)
398 {
399 uint8_t buffer[2];
400 int rc;
401
402 rc = i2c_burst_read_dt(i2c, MLX90394_REG_CID, buffer, ARRAY_SIZE(buffer));
403 if (rc != 0) {
404 LOG_ERR("Failed to read who-am-i register (rc=%d)", rc);
405 return -EIO;
406 }
407
408 if (buffer[0] != MLX90394_CID || buffer[1] != MLX90394_DID) {
409 LOG_ERR("Wrong who-am-i value");
410 return -EINVAL;
411 }
412
413 return 0;
414 }
415
mlx90394_write_read_dt(const struct i2c_dt_spec * i2c,uint8_t start_addr,uint8_t * buffer_write,uint8_t * buffer_read,size_t cnt)416 static int mlx90394_write_read_dt(const struct i2c_dt_spec *i2c, uint8_t start_addr,
417 uint8_t *buffer_write, uint8_t *buffer_read, size_t cnt)
418 {
419 int rc;
420
421 rc = i2c_burst_write_dt(i2c, start_addr, buffer_write, cnt);
422 if (rc != 0) {
423 LOG_ERR("Failed to write %d bytes to register %d (rc=%d)", cnt, start_addr, rc);
424 return -EIO;
425 }
426 rc = i2c_burst_read_dt(i2c, start_addr, buffer_read, cnt);
427 if (rc != 0) {
428 LOG_ERR("Failed to read %d bytes from register %d (rc=%d)", cnt, start_addr, rc);
429 return -EIO;
430 }
431
432 return 0;
433 }
434
mlx90394_sample_fetch_internal(const struct device * dev,enum sensor_channel chan)435 int mlx90394_sample_fetch_internal(const struct device *dev, enum sensor_channel chan)
436 {
437 const struct mlx90394_config *cfg = dev->config;
438 struct mlx90394_data *data = dev->data;
439 int rc;
440
441 if (!data->initialized) {
442 return -ENODEV;
443 }
444
445 rc = i2c_burst_read_dt(&cfg->i2c, MLX90394_REG_STAT1, (uint8_t *)&data->sample,
446 MLX90394_REG_TH + 1);
447 if (rc != 0) {
448 LOG_ERR("Failed to read bytes");
449 return rc;
450 }
451
452 if (FIELD_GET(MLX90394_STAT1_DRDY, data->sample.stat1) != 1) {
453 LOG_ERR("Data was not ready during fetch. In continues mode consider to "
454 "adjust "
455 "sample frequency");
456 return -EIO;
457 }
458 return 0;
459 }
460
mlx90394_trigger_measurement_internal(const struct device * dev,enum sensor_channel chan)461 int mlx90394_trigger_measurement_internal(const struct device *dev, enum sensor_channel chan)
462 {
463 const struct mlx90394_config *cfg = dev->config;
464 struct mlx90394_data *data = dev->data;
465 int rc;
466
467 if (!data->initialized) {
468 return -ENODEV;
469 }
470
471 /*
472 * set single measurement mode as default if not already done
473 */
474 if (FIELD_GET(MLX90394_CTRL1_MODE, data->ctrl_reg_values.ctrl1) !=
475 MLX90394_CTRL1_MODE_SINGLE) {
476 data->ctrl_reg_values.ctrl1 =
477 MLX90394_FIELD_MOD(MLX90394_CTRL1_MODE, MLX90394_CTRL1_MODE_SINGLE,
478 data->ctrl_reg_values.ctrl1);
479 }
480
481 /*
482 * change channel bits and update ctrl4 and the measurement time
483 * if the channel is different than during the last measurement
484 */
485 if (chan != data->channel) {
486 switch (chan) {
487 case SENSOR_CHAN_MAGN_X: {
488 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_X_EN_BIT, 1);
489 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Y_EN_BIT, 0);
490 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Z_EN_BIT, 0);
491 WRITE_BIT(data->ctrl_reg_values.ctrl4, MLX90394_CTRL4_T_EN_BIT, 0);
492 } break;
493 case SENSOR_CHAN_MAGN_Y: {
494 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_X_EN_BIT, 0);
495 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Y_EN_BIT, 1);
496 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Z_EN_BIT, 0);
497 WRITE_BIT(data->ctrl_reg_values.ctrl4, MLX90394_CTRL4_T_EN_BIT, 0);
498 } break;
499 case SENSOR_CHAN_MAGN_Z: {
500 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_X_EN_BIT, 0);
501 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Y_EN_BIT, 0);
502 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Z_EN_BIT, 1);
503 WRITE_BIT(data->ctrl_reg_values.ctrl4, MLX90394_CTRL4_T_EN_BIT, 0);
504 } break;
505 case SENSOR_CHAN_MAGN_XYZ: {
506 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_X_EN_BIT, 1);
507 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Y_EN_BIT, 1);
508 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Z_EN_BIT, 1);
509 WRITE_BIT(data->ctrl_reg_values.ctrl4, MLX90394_CTRL4_T_EN_BIT, 0);
510 } break;
511 case SENSOR_CHAN_AMBIENT_TEMP: {
512 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_X_EN_BIT, 0);
513 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Y_EN_BIT, 0);
514 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Z_EN_BIT, 0);
515 WRITE_BIT(data->ctrl_reg_values.ctrl4, MLX90394_CTRL4_T_EN_BIT, 1);
516 } break;
517 case SENSOR_CHAN_ALL: {
518 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_X_EN_BIT, 1);
519 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Y_EN_BIT, 1);
520 WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Z_EN_BIT, 1);
521 WRITE_BIT(data->ctrl_reg_values.ctrl4, MLX90394_CTRL4_T_EN_BIT, 1);
522 } break;
523 default: {
524 return -ENOTSUP;
525 }
526 }
527 rc = i2c_reg_write_byte_dt(&cfg->i2c, MLX90394_REG_CTRL4,
528 data->ctrl_reg_values.ctrl4);
529 if (rc != 0) {
530 LOG_ERR("Failed to write ctrl4");
531 return rc;
532 }
533
534 data->channel = chan;
535 mlx90394_update_measurement_Time_us(data);
536 }
537
538 rc = i2c_reg_write_byte_dt(&cfg->i2c, MLX90394_REG_CTRL1, data->ctrl_reg_values.ctrl1);
539 if (rc != 0) {
540 LOG_ERR("Failed to write ctrl1");
541 }
542
543 return rc;
544 }
545
mlx90394_sample_fetch(const struct device * dev,enum sensor_channel chan)546 static int mlx90394_sample_fetch(const struct device *dev, enum sensor_channel chan)
547 {
548 int rc;
549 struct mlx90394_data *data = dev->data;
550
551 rc = mlx90394_trigger_measurement_internal(dev, chan);
552 if (rc != 0) {
553 return rc;
554 }
555
556 k_usleep(data->measurement_time_us);
557 rc = mlx90394_sample_fetch_internal(dev, chan);
558
559 return rc;
560 }
561
mlx90394_init(const struct device * dev)562 static int mlx90394_init(const struct device *dev)
563 {
564 const struct mlx90394_config *cfg = dev->config;
565 struct mlx90394_data *data = dev->data;
566 int rc;
567
568 if (!i2c_is_ready_dt(&cfg->i2c)) {
569 LOG_ERR("I2C bus device not ready");
570 return -ENODEV;
571 }
572
573 /*
574 * Soft reset the chip
575 */
576 rc = i2c_reg_write_byte_dt(&cfg->i2c, MLX90394_REG_RST, MLX90394_RST);
577 if (rc != 0) {
578 LOG_ERR("Failed to soft reset");
579 return -EIO;
580 }
581 k_usleep(MLX90394_STARTUP_TIME_US);
582
583 /*
584 * check chip ID
585 */
586 rc = mlx90394_check_who_am_i(&cfg->i2c);
587 if (rc != 0) {
588 return rc;
589 }
590
591 /*
592 * set all to default and read the settings back
593 */
594 rc = mlx90394_write_read_dt(&cfg->i2c, MLX90394_REG_CTRL1,
595 (uint8_t *)&data->ctrl_reg_values.ctrl1,
596 (uint8_t *)&data->ctrl_reg_values.ctrl1, 2);
597 if (rc != 0) {
598 return rc;
599 }
600
601 rc = mlx90394_write_read_dt(&cfg->i2c, MLX90394_REG_CTRL3,
602 (uint8_t *)&data->ctrl_reg_values.ctrl3,
603 (uint8_t *)&data->ctrl_reg_values.ctrl3, 2);
604 if (rc != 0) {
605 return rc;
606 }
607
608 mlx90394_update_measurement_Time_us(data);
609
610 #ifdef CONFIG_SENSOR_ASYNC_API
611 data->dev = dev;
612 /*
613 * init work for fetching after measurement has completed
614 */
615 k_work_init_delayable(&data->async_fetch_work, mlx90394_async_fetch);
616 #endif
617 data->initialized = true;
618 return 0;
619 }
620
621 static DEVICE_API(sensor, mlx90394_driver_api) = {
622 .sample_fetch = mlx90394_sample_fetch,
623 .channel_get = mlx90394_channel_get,
624 .attr_get = mlx90394_attr_get,
625 .attr_set = mlx90394_attr_set,
626 #ifdef CONFIG_SENSOR_ASYNC_API
627 .submit = mlx90394_submit,
628 .get_decoder = mlx90394_get_decoder,
629 #endif
630 };
631
632 #define MLX90394_DEFINE(inst) \
633 static struct mlx90394_data mlx90394_data_##inst = { \
634 .sample = {.x_l = 0, \
635 .x_h = 0, \
636 .y_l = 0, \
637 .y_h = 0, \
638 .z_l = 0, \
639 .z_h = 0, \
640 .temp_l = 0, \
641 .temp_h = 0}, \
642 .channel = SENSOR_CHAN_MAGN_XYZ, \
643 .config_val = FIELD_GET(MLX90394_CTRL2_CONFIG, MLX90394_CTRL2_DEFAULT), \
644 .measurement_time_us = 0, \
645 .ctrl_reg_values = {.ctrl1 = MLX90394_CTRL1_DEFAULT, \
646 .ctrl2 = MLX90394_CTRL2_DEFAULT, \
647 .ctrl3 = MLX90394_CTRL3_DEFAULT, \
648 .ctrl4 = MLX90394_CTRL4_DEFAULT}, \
649 .initialized = false}; \
650 static const struct mlx90394_config mlx90394_config_##inst = { \
651 .i2c = I2C_DT_SPEC_INST_GET(inst)}; \
652 SENSOR_DEVICE_DT_INST_DEFINE(inst, mlx90394_init, NULL, &mlx90394_data_##inst, \
653 &mlx90394_config_##inst, POST_KERNEL, \
654 CONFIG_SENSOR_INIT_PRIORITY, &mlx90394_driver_api);
655
656 DT_INST_FOREACH_STATUS_OKAY(MLX90394_DEFINE)
657