1 /* bmc150_magn.c - Driver for Bosch BMC150 magnetometer sensor */
2
3 /*
4 * Copyright (c) 2016 Intel Corporation
5 *
6 * This code is based on bmm050.c from:
7 * https://github.com/BoschSensortec/BMM050_driver
8 *
9 * SPDX-License-Identifier: Apache-2.0
10 */
11
12 #define DT_DRV_COMPAT bosch_bmc150_magn
13
14 #include <zephyr/drivers/sensor.h>
15 #include <zephyr/kernel.h>
16 #include <zephyr/device.h>
17 #include <zephyr/init.h>
18 #include <zephyr/sys/byteorder.h>
19 #include <zephyr/sys/__assert.h>
20
21 #include <zephyr/drivers/gpio.h>
22 #include <zephyr/logging/log.h>
23
24 #include "bmc150_magn.h"
25
26 LOG_MODULE_REGISTER(BMC150_MAGN, CONFIG_SENSOR_LOG_LEVEL);
27
28 static const struct {
29 int freq;
30 uint8_t reg_val;
31 } bmc150_magn_samp_freq_table[] = { {2, 0x01},
32 {6, 0x02},
33 {8, 0x03},
34 {10, 0x00},
35 {15, 0x04},
36 {20, 0x05},
37 {25, 0x06},
38 {30, 0x07} };
39
40 static const struct bmc150_magn_preset {
41 uint8_t rep_xy;
42 uint8_t rep_z;
43 uint8_t odr;
44 } bmc150_magn_presets_table[] = {
45 [LOW_POWER_PRESET] = {3, 3, 10},
46 [REGULAR_PRESET] = {9, 15, 10},
47 [ENHANCED_REGULAR_PRESET] = {15, 27, 10},
48 [HIGH_ACCURACY_PRESET] = {47, 83, 20}
49 };
50
bmc150_magn_set_power_mode(const struct device * dev,enum bmc150_magn_power_modes mode,int state)51 static int bmc150_magn_set_power_mode(const struct device *dev,
52 enum bmc150_magn_power_modes mode,
53 int state)
54 {
55 const struct bmc150_magn_config *config = dev->config;
56
57 switch (mode) {
58 case BMC150_MAGN_POWER_MODE_SUSPEND:
59 if (i2c_reg_update_byte_dt(&config->i2c,
60 BMC150_MAGN_REG_POWER,
61 BMC150_MAGN_MASK_POWER_CTL,
62 !state) < 0) {
63 return -EIO;
64 }
65 k_busy_wait(USEC_PER_MSEC * 5U);
66
67 return 0;
68 case BMC150_MAGN_POWER_MODE_SLEEP:
69 return i2c_reg_update_byte_dt(&config->i2c,
70 BMC150_MAGN_REG_OPMODE_ODR,
71 BMC150_MAGN_MASK_OPMODE,
72 BMC150_MAGN_MODE_SLEEP <<
73 BMC150_MAGN_SHIFT_OPMODE);
74 break;
75 case BMC150_MAGN_POWER_MODE_NORMAL:
76 return i2c_reg_update_byte_dt(&config->i2c,
77 BMC150_MAGN_REG_OPMODE_ODR,
78 BMC150_MAGN_MASK_OPMODE,
79 BMC150_MAGN_MODE_NORMAL <<
80 BMC150_MAGN_SHIFT_OPMODE);
81 break;
82 }
83
84 return -ENOTSUP;
85 }
86
bmc150_magn_set_odr(const struct device * dev,uint8_t val)87 static int bmc150_magn_set_odr(const struct device *dev, uint8_t val)
88 {
89 const struct bmc150_magn_config *config = dev->config;
90 uint8_t i;
91
92 for (i = 0U; i < ARRAY_SIZE(bmc150_magn_samp_freq_table); ++i) {
93 if (val <= bmc150_magn_samp_freq_table[i].freq) {
94 return i2c_reg_update_byte_dt(&config->i2c,
95 BMC150_MAGN_REG_OPMODE_ODR,
96 BMC150_MAGN_MASK_ODR,
97 bmc150_magn_samp_freq_table[i].reg_val
98 << BMC150_MAGN_SHIFT_ODR);
99 }
100 }
101
102 return -ENOTSUP;
103 }
104
105 #if defined(BMC150_MAGN_SET_ATTR)
bmc150_magn_read_rep_xy(const struct device * dev)106 static int bmc150_magn_read_rep_xy(const struct device *dev)
107 {
108 struct bmc150_magn_data *data = dev->data;
109 const struct bmc150_magn_config *config = dev->config;
110 uint8_t reg_val;
111
112 if (i2c_reg_read_byte_dt(&config->i2c,
113 BMC150_MAGN_REG_REP_XY, ®_val) < 0) {
114 return -EIO;
115 }
116
117 data->rep_xy = BMC150_MAGN_REGVAL_TO_REPXY((int)(reg_val));
118
119 return 0;
120 }
121
bmc150_magn_read_rep_z(const struct device * dev)122 static int bmc150_magn_read_rep_z(const struct device *dev)
123 {
124 struct bmc150_magn_data *data = dev->data;
125 const struct bmc150_magn_config *config = dev->config;
126 uint8_t reg_val;
127
128 if (i2c_reg_read_byte_dt(&config->i2c,
129 BMC150_MAGN_REG_REP_Z, ®_val) < 0) {
130 return -EIO;
131 }
132
133 data->rep_z = BMC150_MAGN_REGVAL_TO_REPZ((int)(reg_val));
134
135 return 0;
136 }
137
bmc150_magn_compute_max_odr(const struct device * dev,int rep_xy,int rep_z,int * max_odr)138 static int bmc150_magn_compute_max_odr(const struct device *dev, int rep_xy,
139 int rep_z, int *max_odr)
140 {
141 struct bmc150_magn_data *data = dev->data;
142
143 if (rep_xy == 0) {
144 if (data->rep_xy <= 0) {
145 if (bmc150_magn_read_rep_xy(dev) < 0) {
146 return -EIO;
147 }
148 }
149 rep_xy = data->rep_xy;
150 }
151
152 if (rep_z == 0) {
153 if (data->rep_z <= 0) {
154 if (bmc150_magn_read_rep_z(dev) < 0) {
155 return -EIO;
156 }
157 }
158 rep_z = data->rep_z;
159 }
160
161 *max_odr = 1000000 / (145 * rep_xy + 500 * rep_z + 980);
162
163 return 0;
164 }
165 #endif
166
167 #if defined(BMC150_MAGN_SET_ATTR_REP)
bmc150_magn_read_odr(const struct device * dev)168 static int bmc150_magn_read_odr(const struct device *dev)
169 {
170 struct bmc150_magn_data *data = dev->data;
171 const struct bmc150_magn_config *config = dev->config;
172 uint8_t i, odr_val, reg_val;
173
174 if (i2c_reg_read_byte_dt(&config->i2c,
175 BMC150_MAGN_REG_OPMODE_ODR, ®_val) < 0) {
176 return -EIO;
177 }
178
179 odr_val = (reg_val & BMC150_MAGN_MASK_ODR) >> BMC150_MAGN_SHIFT_ODR;
180
181 for (i = 0U; i < ARRAY_SIZE(bmc150_magn_samp_freq_table); ++i) {
182 if (bmc150_magn_samp_freq_table[i].reg_val == odr_val) {
183 data->odr = bmc150_magn_samp_freq_table[i].freq;
184 return 0;
185 }
186 }
187
188 return -ENOTSUP;
189 }
190 #endif
191
192 #if defined(CONFIG_BMC150_MAGN_SAMPLING_REP_XY)
bmc150_magn_write_rep_xy(const struct device * dev,int val)193 static int bmc150_magn_write_rep_xy(const struct device *dev, int val)
194 {
195 struct bmc150_magn_data *data = dev->data;
196 const struct bmc150_magn_config *config = dev->config;
197
198 if (i2c_reg_update_byte_dt(&config->i2c,
199 BMC150_MAGN_REG_REP_XY,
200 BMC150_MAGN_REG_REP_DATAMASK,
201 BMC150_MAGN_REPXY_TO_REGVAL(val)) < 0) {
202 return -EIO;
203 }
204
205 data->rep_xy = val;
206
207 return 0;
208 }
209 #endif
210
211 #if defined(CONFIG_BMC150_MAGN_SAMPLING_REP_Z)
bmc150_magn_write_rep_z(const struct device * dev,int val)212 static int bmc150_magn_write_rep_z(const struct device *dev, int val)
213 {
214 struct bmc150_magn_data *data = dev->data;
215 const struct bmc150_magn_config *config = dev->config;
216
217 if (i2c_reg_update_byte_dt(&config->i2c,
218 BMC150_MAGN_REG_REP_Z,
219 BMC150_MAGN_REG_REP_DATAMASK,
220 BMC150_MAGN_REPZ_TO_REGVAL(val)) < 0) {
221 return -EIO;
222 }
223
224 data->rep_z = val;
225
226 return 0;
227 }
228 #endif
229
230 /*
231 * Datasheet part 4.3.4, provided by Bosch here:
232 * https://github.com/BoschSensortec/BMM050_driver
233 */
bmc150_magn_compensate_xy(struct bmc150_magn_trim_regs * tregs,int16_t xy,uint16_t rhall,bool is_x)234 static int32_t bmc150_magn_compensate_xy(struct bmc150_magn_trim_regs *tregs,
235 int16_t xy, uint16_t rhall, bool is_x)
236 {
237 int8_t txy1, txy2;
238 int16_t val;
239
240 if (xy == BMC150_MAGN_XY_OVERFLOW_VAL) {
241 return INT32_MIN;
242 }
243
244 if (!rhall) {
245 rhall = tregs->xyz1;
246 }
247
248 if (is_x) {
249 txy1 = tregs->x1;
250 txy2 = tregs->x2;
251 } else {
252 txy1 = tregs->y1;
253 txy2 = tregs->y2;
254 }
255
256 val = ((int16_t)(((uint16_t)((((int32_t)tregs->xyz1) << 14) / rhall)) -
257 ((uint16_t)0x4000)));
258 val = ((int16_t)((((int32_t)xy) * ((((((((int32_t)tregs->xy2) *
259 ((((int32_t)val) * ((int32_t)val)) >> 7)) + (((int32_t)val) *
260 ((int32_t)(((int16_t)tregs->xy1) << 7)))) >> 9) +
261 ((int32_t)0x100000)) * ((int32_t)(((int16_t)txy2) +
262 ((int16_t)0xA0)))) >> 12)) >> 13)) + (((int16_t)txy1) << 3);
263
264 return (int32_t)val;
265 }
266
bmc150_magn_compensate_z(struct bmc150_magn_trim_regs * tregs,int16_t z,uint16_t rhall)267 static int32_t bmc150_magn_compensate_z(struct bmc150_magn_trim_regs *tregs,
268 int16_t z, uint16_t rhall)
269 {
270 int32_t val;
271
272 if (z == BMC150_MAGN_Z_OVERFLOW_VAL) {
273 return INT32_MIN;
274 }
275
276 val = (((((int32_t)(z - tregs->z4)) << 15) - ((((int32_t)tregs->z3) *
277 ((int32_t)(((int16_t)rhall) - ((int16_t)tregs->xyz1)))) >> 2)) /
278 (tregs->z2 + ((int16_t)(((((int32_t)tregs->z1) *
279 ((((int16_t)rhall) << 1))) + (1 << 15)) >> 16))));
280
281 return val;
282 }
283
bmc150_magn_sample_fetch(const struct device * dev,enum sensor_channel chan)284 static int bmc150_magn_sample_fetch(const struct device *dev,
285 enum sensor_channel chan)
286 {
287 struct bmc150_magn_data *data = dev->data;
288 const struct bmc150_magn_config *config = dev->config;
289 uint16_t values[BMC150_MAGN_AXIS_XYZR_MAX];
290 int16_t raw_x, raw_y, raw_z;
291 uint16_t rhall;
292
293 __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL ||
294 chan == SENSOR_CHAN_MAGN_XYZ);
295
296 if (i2c_burst_read_dt(&config->i2c,
297 BMC150_MAGN_REG_X_L, (uint8_t *)values,
298 sizeof(values)) < 0) {
299 LOG_ERR("failed to read sample");
300 return -EIO;
301 }
302
303 raw_x = (int16_t)sys_le16_to_cpu(values[BMC150_MAGN_AXIS_X]) >>
304 BMC150_MAGN_SHIFT_XY_L;
305 raw_y = (int16_t)sys_le16_to_cpu(values[BMC150_MAGN_AXIS_Y]) >>
306 BMC150_MAGN_SHIFT_XY_L;
307 raw_z = (int16_t)sys_le16_to_cpu(values[BMC150_MAGN_AXIS_Z]) >>
308 BMC150_MAGN_SHIFT_Z_L;
309 rhall = sys_le16_to_cpu(values[BMC150_MAGN_RHALL]) >>
310 BMC150_MAGN_SHIFT_RHALL_L;
311
312 data->sample_x = bmc150_magn_compensate_xy(&data->tregs, raw_x, rhall,
313 true);
314 data->sample_y = bmc150_magn_compensate_xy(&data->tregs, raw_y, rhall,
315 false);
316 data->sample_z = bmc150_magn_compensate_z(&data->tregs, raw_z, rhall);
317
318 return 0;
319 }
320
bmc150_magn_convert(struct sensor_value * val,int raw_val)321 static void bmc150_magn_convert(struct sensor_value *val, int raw_val)
322 {
323 /* val = raw_val / 1600 */
324 val->val1 = raw_val / 1600;
325 val->val2 = ((int32_t)raw_val * (1000000 / 1600)) % 1000000;
326 }
327
bmc150_magn_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)328 static int bmc150_magn_channel_get(const struct device *dev,
329 enum sensor_channel chan,
330 struct sensor_value *val)
331 {
332 struct bmc150_magn_data *data = dev->data;
333
334 switch (chan) {
335 case SENSOR_CHAN_MAGN_X:
336 bmc150_magn_convert(val, data->sample_x);
337 break;
338 case SENSOR_CHAN_MAGN_Y:
339 bmc150_magn_convert(val, data->sample_y);
340 break;
341 case SENSOR_CHAN_MAGN_Z:
342 bmc150_magn_convert(val, data->sample_z);
343 break;
344 case SENSOR_CHAN_MAGN_XYZ:
345 bmc150_magn_convert(val, data->sample_x);
346 bmc150_magn_convert(val + 1, data->sample_y);
347 bmc150_magn_convert(val + 2, data->sample_z);
348 break;
349 default:
350 return -ENOTSUP;
351 }
352
353 return 0;
354 }
355
356 #if defined(BMC150_MAGN_SET_ATTR_REP)
bmc150_magn_attr_set_rep(const struct device * dev,enum sensor_channel chan,const struct sensor_value * val)357 static inline int bmc150_magn_attr_set_rep(const struct device *dev,
358 enum sensor_channel chan,
359 const struct sensor_value *val)
360 {
361 struct bmc150_magn_data *data = dev->data;
362 int max_odr;
363
364 switch (chan) {
365 #if defined(CONFIG_BMC150_MAGN_SAMPLING_REP_XY)
366 case SENSOR_CHAN_MAGN_X:
367 case SENSOR_CHAN_MAGN_Y:
368 if (val->val1 < 1 || val->val1 > 511) {
369 return -EINVAL;
370 }
371
372 if (bmc150_magn_compute_max_odr(dev, val->val1, 0,
373 &max_odr) < 0) {
374 return -EIO;
375 }
376
377 if (data->odr <= 0) {
378 if (bmc150_magn_read_odr(dev) < 0) {
379 return -EIO;
380 }
381 }
382
383 if (data->odr > max_odr) {
384 return -EINVAL;
385 }
386
387 if (bmc150_magn_write_rep_xy(dev, val->val1) < 0) {
388 return -EIO;
389 }
390 break;
391 #endif
392 #if defined(CONFIG_BMC150_MAGN_SAMPLING_REP_Z)
393 case SENSOR_CHAN_MAGN_Z:
394 if (val->val1 < 1 || val->val1 > 256) {
395 return -EINVAL;
396 }
397
398 if (bmc150_magn_compute_max_odr(dev, 0, val->val1,
399 &max_odr) < 0) {
400 return -EIO;
401 }
402
403 if (data->odr <= 0) {
404 if (bmc150_magn_read_odr(dev) < 0) {
405 return -EIO;
406 }
407 }
408
409 if (data->odr > max_odr) {
410 return -EINVAL;
411 }
412
413 if (bmc150_magn_write_rep_z(dev, val->val1) < 0) {
414 return -EIO;
415 }
416 break;
417 #endif
418 default:
419 return -EINVAL;
420 }
421
422 return 0;
423 }
424 #endif
425
426 #if defined(BMC150_MAGN_SET_ATTR)
bmc150_magn_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)427 static int bmc150_magn_attr_set(const struct device *dev,
428 enum sensor_channel chan,
429 enum sensor_attribute attr,
430 const struct sensor_value *val)
431 {
432 struct bmc150_magn_data *data = dev->data;
433
434 switch (attr) {
435 #if defined(CONFIG_BMC150_MAGN_SAMPLING_RATE_RUNTIME)
436 case SENSOR_ATTR_SAMPLING_FREQUENCY:
437 if (data->max_odr <= 0) {
438 if (bmc150_magn_compute_max_odr(dev, 0, 0,
439 &data->max_odr) < 0) {
440 return -EIO;
441 }
442 }
443
444 if (data->max_odr < val->val1) {
445 LOG_ERR("not supported with current oversampling");
446 return -ENOTSUP;
447 }
448
449 if (bmc150_magn_set_odr(dev, (uint8_t)(val->val1)) < 0) {
450 return -EIO;
451 }
452 break;
453 #endif
454 #if defined(BMC150_MAGN_SET_ATTR_REP)
455 case SENSOR_ATTR_OVERSAMPLING:
456 bmc150_magn_attr_set_rep(dev, chan, val);
457 break;
458 #endif
459 default:
460 return -EINVAL;
461 }
462
463 return 0;
464 }
465 #endif
466
467 static DEVICE_API(sensor, bmc150_magn_api_funcs) = {
468 #if defined(BMC150_MAGN_SET_ATTR)
469 .attr_set = bmc150_magn_attr_set,
470 #endif
471 .sample_fetch = bmc150_magn_sample_fetch,
472 .channel_get = bmc150_magn_channel_get,
473 #if defined(CONFIG_BMC150_MAGN_TRIGGER_DRDY)
474 .trigger_set = bmc150_magn_trigger_set,
475 #endif
476 };
477
bmc150_magn_init_chip(const struct device * dev)478 static int bmc150_magn_init_chip(const struct device *dev)
479 {
480 struct bmc150_magn_data *data = dev->data;
481 const struct bmc150_magn_config *config = dev->config;
482 uint8_t chip_id;
483 struct bmc150_magn_preset preset;
484
485 bmc150_magn_set_power_mode(dev, BMC150_MAGN_POWER_MODE_NORMAL, 0);
486 bmc150_magn_set_power_mode(dev, BMC150_MAGN_POWER_MODE_SUSPEND, 1);
487
488 if (bmc150_magn_set_power_mode(dev, BMC150_MAGN_POWER_MODE_SUSPEND, 0)
489 < 0) {
490 LOG_ERR("failed to bring up device from suspend mode");
491 return -EIO;
492 }
493
494 if (i2c_reg_read_byte_dt(&config->i2c,
495 BMC150_MAGN_REG_CHIP_ID, &chip_id) < 0) {
496 LOG_ERR("failed reading chip id");
497 goto err_poweroff;
498 }
499 if (chip_id != BMC150_MAGN_CHIP_ID_VAL) {
500 LOG_ERR("invalid chip id 0x%x", chip_id);
501 goto err_poweroff;
502 }
503 LOG_ERR("chip id 0x%x", chip_id);
504
505 preset = bmc150_magn_presets_table[BMC150_MAGN_DEFAULT_PRESET];
506 if (bmc150_magn_set_odr(dev, preset.odr) < 0) {
507 LOG_ERR("failed to set ODR to %d",
508 preset.odr);
509 goto err_poweroff;
510 }
511
512 if (i2c_reg_write_byte_dt(&config->i2c,
513 BMC150_MAGN_REG_REP_XY,
514 BMC150_MAGN_REPXY_TO_REGVAL(preset.rep_xy))
515 < 0) {
516 LOG_ERR("failed to set REP XY to %d",
517 preset.rep_xy);
518 goto err_poweroff;
519 }
520
521 if (i2c_reg_write_byte_dt(&config->i2c,
522 BMC150_MAGN_REG_REP_Z,
523 BMC150_MAGN_REPZ_TO_REGVAL(preset.rep_z)) < 0) {
524 LOG_ERR("failed to set REP Z to %d",
525 preset.rep_z);
526 goto err_poweroff;
527 }
528
529 if (bmc150_magn_set_power_mode(dev, BMC150_MAGN_POWER_MODE_NORMAL, 1)
530 < 0) {
531 LOG_ERR("failed to power on device");
532 goto err_poweroff;
533 }
534
535 if (i2c_burst_read_dt(&config->i2c,
536 BMC150_MAGN_REG_TRIM_START, (uint8_t *)&data->tregs,
537 sizeof(data->tregs)) < 0) {
538 LOG_ERR("failed to read trim regs");
539 goto err_poweroff;
540 }
541
542 data->rep_xy = 0;
543 data->rep_z = 0;
544 data->odr = 0;
545 data->max_odr = 0;
546 data->sample_x = 0;
547 data->sample_y = 0;
548 data->sample_z = 0;
549
550 data->tregs.xyz1 = sys_le16_to_cpu(data->tregs.xyz1);
551 data->tregs.z1 = sys_le16_to_cpu(data->tregs.z1);
552 data->tregs.z2 = sys_le16_to_cpu(data->tregs.z2);
553 data->tregs.z3 = sys_le16_to_cpu(data->tregs.z3);
554 data->tregs.z4 = sys_le16_to_cpu(data->tregs.z4);
555
556 return 0;
557
558 err_poweroff:
559 bmc150_magn_set_power_mode(dev, BMC150_MAGN_POWER_MODE_NORMAL, 0);
560 bmc150_magn_set_power_mode(dev, BMC150_MAGN_POWER_MODE_SUSPEND, 1);
561 return -EIO;
562 }
563
bmc150_magn_init(const struct device * dev)564 static int bmc150_magn_init(const struct device *dev)
565 {
566 const struct bmc150_magn_config * const config =
567 dev->config;
568
569 if (!device_is_ready(config->i2c.bus)) {
570 LOG_ERR("I2C bus device not ready");
571 return -ENODEV;
572 }
573
574 if (bmc150_magn_init_chip(dev) < 0) {
575 LOG_ERR("failed to initialize chip");
576 return -EIO;
577 }
578
579 #if defined(CONFIG_BMC150_MAGN_TRIGGER_DRDY)
580 if (config->int_gpio.port) {
581 if (bmc150_magn_init_interrupt(dev) < 0) {
582 LOG_ERR("failed to initialize interrupts");
583 return -EINVAL;
584 }
585 }
586 #endif
587 return 0;
588 }
589
590 #define BMC150_MAGN_DEFINE(inst) \
591 static struct bmc150_magn_data bmc150_magn_data_##inst; \
592 \
593 static const struct bmc150_magn_config bmc150_magn_config_##inst = { \
594 .i2c = I2C_DT_SPEC_INST_GET(inst), \
595 IF_ENABLED(CONFIG_BMC150_MAGN_TRIGGER_DRDY, \
596 (.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, drdy_gpios, { 0 }),)) \
597 }; \
598 \
599 SENSOR_DEVICE_DT_INST_DEFINE(inst, bmc150_magn_init, NULL, \
600 &bmc150_magn_data_##inst, &bmc150_magn_config_##inst, POST_KERNEL, \
601 CONFIG_SENSOR_INIT_PRIORITY, &bmc150_magn_api_funcs); \
602
603 DT_INST_FOREACH_STATUS_OKAY(BMC150_MAGN_DEFINE)
604