1 /* ST Microelectronics LIS2MDL 3-axis magnetometer sensor
2 *
3 * Copyright (c) 2018-2019 STMicroelectronics
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Datasheet:
8 * https://www.st.com/resource/en/datasheet/lis2mdl.pdf
9 */
10
11 #define DT_DRV_COMPAT st_lis2mdl
12
13 #include <zephyr/init.h>
14 #include <zephyr/sys/__assert.h>
15 #include <zephyr/sys/byteorder.h>
16 #include <zephyr/drivers/sensor.h>
17 #include <zephyr/pm/device.h>
18 #include <string.h>
19 #include <zephyr/logging/log.h>
20 #include "lis2mdl.h"
21
22 /* Based on the data sheet, the maximum turn-on time is ("9.4 ms + 1/ODR") when
23 * offset cancellation is on. But in the single mode the ODR is not dependent on
24 * the configured value in Reg A. It is dependent on the frequency of the I2C
25 * signal. The slowest value we could measure by I2C frequency of 100000HZ was
26 * 13 ms. So we chose 20 ms.
27 */
28 #define SAMPLE_FETCH_TIMEOUT_MS 20
29
30 struct lis2mdl_data lis2mdl_data;
31
32 LOG_MODULE_REGISTER(LIS2MDL, CONFIG_SENSOR_LOG_LEVEL);
33
34 #ifdef CONFIG_LIS2MDL_MAG_ODR_RUNTIME
lis2mdl_set_odr(const struct device * dev,const struct sensor_value * val)35 static int lis2mdl_set_odr(const struct device *dev,
36 const struct sensor_value *val)
37 {
38 const struct lis2mdl_config *cfg = dev->config;
39 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
40 lis2mdl_odr_t odr;
41
42 switch (val->val1) {
43 case 10:
44 odr = LIS2MDL_ODR_10Hz;
45 break;
46 case 20:
47 odr = LIS2MDL_ODR_20Hz;
48 break;
49 case 50:
50 odr = LIS2MDL_ODR_50Hz;
51 break;
52 case 100:
53 odr = LIS2MDL_ODR_100Hz;
54 break;
55 default:
56 return -EINVAL;
57 }
58
59 if (lis2mdl_data_rate_set(ctx, odr)) {
60 return -EIO;
61 }
62
63 return 0;
64 }
65 #endif /* CONFIG_LIS2MDL_MAG_ODR_RUNTIME */
66
lis2mdl_set_hard_iron(const struct device * dev,enum sensor_channel chan,const struct sensor_value * val)67 static int lis2mdl_set_hard_iron(const struct device *dev,
68 enum sensor_channel chan,
69 const struct sensor_value *val)
70 {
71 const struct lis2mdl_config *cfg = dev->config;
72 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
73 uint8_t i;
74 int16_t offset[3];
75
76 for (i = 0U; i < 3; i++) {
77 offset[i] = sys_cpu_to_le16(val->val1);
78 val++;
79 }
80
81 return lis2mdl_mag_user_offset_set(ctx, offset);
82 }
83
lis2mdl_channel_get_mag(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)84 static void lis2mdl_channel_get_mag(const struct device *dev,
85 enum sensor_channel chan,
86 struct sensor_value *val)
87 {
88 int32_t cval;
89 int i;
90 uint8_t ofs_start, ofs_stop;
91 struct lis2mdl_data *lis2mdl = dev->data;
92 struct sensor_value *pval = val;
93
94 switch (chan) {
95 case SENSOR_CHAN_MAGN_X:
96 ofs_start = ofs_stop = 0U;
97 break;
98 case SENSOR_CHAN_MAGN_Y:
99 ofs_start = ofs_stop = 1U;
100 break;
101 case SENSOR_CHAN_MAGN_Z:
102 ofs_start = ofs_stop = 2U;
103 break;
104 default:
105 ofs_start = 0U; ofs_stop = 2U;
106 break;
107 }
108
109 for (i = ofs_start; i <= ofs_stop; i++) {
110 cval = lis2mdl->mag[i] * 1500;
111 pval->val1 = cval / 1000000;
112 pval->val2 = cval % 1000000;
113 pval++;
114 }
115 }
116
117 /* read internal temperature */
lis2mdl_channel_get_temp(const struct device * dev,struct sensor_value * val)118 static void lis2mdl_channel_get_temp(const struct device *dev,
119 struct sensor_value *val)
120 {
121 struct lis2mdl_data *drv_data = dev->data;
122
123 /* formula is temp = 25 + (temp / 8) C */
124 val->val1 = 25 + drv_data->temp_sample / 8;
125 val->val2 = (drv_data->temp_sample % 8) * 1000000 / 8;
126 }
127
lis2mdl_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)128 static int lis2mdl_channel_get(const struct device *dev,
129 enum sensor_channel chan,
130 struct sensor_value *val)
131 {
132 switch (chan) {
133 case SENSOR_CHAN_MAGN_X:
134 case SENSOR_CHAN_MAGN_Y:
135 case SENSOR_CHAN_MAGN_Z:
136 case SENSOR_CHAN_MAGN_XYZ:
137 lis2mdl_channel_get_mag(dev, chan, val);
138 break;
139 case SENSOR_CHAN_DIE_TEMP:
140 lis2mdl_channel_get_temp(dev, val);
141 break;
142 default:
143 LOG_ERR("Channel not supported");
144 return -ENOTSUP;
145 }
146
147 return 0;
148 }
149
lis2mdl_config(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)150 static int lis2mdl_config(const struct device *dev, enum sensor_channel chan,
151 enum sensor_attribute attr,
152 const struct sensor_value *val)
153 {
154 switch (attr) {
155 #ifdef CONFIG_LIS2MDL_MAG_ODR_RUNTIME
156 case SENSOR_ATTR_SAMPLING_FREQUENCY:
157 return lis2mdl_set_odr(dev, val);
158 #endif /* CONFIG_LIS2MDL_MAG_ODR_RUNTIME */
159 case SENSOR_ATTR_OFFSET:
160 return lis2mdl_set_hard_iron(dev, chan, val);
161 default:
162 LOG_ERR("Mag attribute not supported");
163 return -ENOTSUP;
164 }
165
166 return 0;
167 }
168
lis2mdl_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)169 static int lis2mdl_attr_set(const struct device *dev,
170 enum sensor_channel chan,
171 enum sensor_attribute attr,
172 const struct sensor_value *val)
173 {
174 switch (chan) {
175 case SENSOR_CHAN_ALL:
176 case SENSOR_CHAN_MAGN_X:
177 case SENSOR_CHAN_MAGN_Y:
178 case SENSOR_CHAN_MAGN_Z:
179 case SENSOR_CHAN_MAGN_XYZ:
180 return lis2mdl_config(dev, chan, attr, val);
181 default:
182 LOG_ERR("attr_set() not supported on %d channel", chan);
183 return -ENOTSUP;
184 }
185
186 return 0;
187 }
188
get_single_mode_raw_data(const struct device * dev,int16_t * raw_mag)189 static int get_single_mode_raw_data(const struct device *dev,
190 int16_t *raw_mag)
191 {
192 struct lis2mdl_data *lis2mdl = dev->data;
193 const struct lis2mdl_config *cfg = dev->config;
194 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
195 int rc = 0;
196
197 rc = lis2mdl_operating_mode_set(ctx, LIS2MDL_SINGLE_TRIGGER);
198 if (rc) {
199 LOG_ERR("set single mode failed");
200 return rc;
201 }
202
203 if (k_sem_take(&lis2mdl->fetch_sem, K_MSEC(SAMPLE_FETCH_TIMEOUT_MS))) {
204 LOG_ERR("Magnetometer data not ready within %d ms",
205 SAMPLE_FETCH_TIMEOUT_MS);
206 return -EIO;
207 }
208
209 /* fetch raw data sample */
210 rc = lis2mdl_magnetic_raw_get(ctx, raw_mag);
211 if (rc) {
212 LOG_ERR("Failed to read sample");
213 return rc;
214 }
215 return 0;
216 }
217
lis2mdl_sample_fetch_mag(const struct device * dev)218 static int lis2mdl_sample_fetch_mag(const struct device *dev)
219 {
220 struct lis2mdl_data *lis2mdl = dev->data;
221 const struct lis2mdl_config *cfg = dev->config;
222 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
223 int16_t raw_mag[3];
224 int rc = 0;
225
226 if (cfg->single_mode) {
227 rc = get_single_mode_raw_data(dev, raw_mag);
228 if (rc) {
229 LOG_ERR("Failed to read raw data");
230 return rc;
231 }
232 lis2mdl->mag[0] = sys_le16_to_cpu(raw_mag[0]);
233 lis2mdl->mag[1] = sys_le16_to_cpu(raw_mag[1]);
234 lis2mdl->mag[2] = sys_le16_to_cpu(raw_mag[2]);
235
236 if (cfg->cancel_offset) {
237 /* The second measurement is needed when offset
238 * cancellation is enabled in the single mode. Then the
239 * average of the first measurement done above and this
240 * one would be the final value. This process is not
241 * needed in continuous mode since it has been taken
242 * care by lis2mdl itself automatically. Please refer
243 * to the application note for more details.
244 */
245 rc = get_single_mode_raw_data(dev, raw_mag);
246 if (rc) {
247 LOG_ERR("Failed to read raw data");
248 return rc;
249 }
250 lis2mdl->mag[0] += sys_le16_to_cpu(raw_mag[0]);
251 lis2mdl->mag[1] += sys_le16_to_cpu(raw_mag[1]);
252 lis2mdl->mag[2] += sys_le16_to_cpu(raw_mag[2]);
253 lis2mdl->mag[0] /= 2;
254 lis2mdl->mag[1] /= 2;
255 lis2mdl->mag[2] /= 2;
256 }
257
258 } else {
259 /* fetch raw data sample */
260 rc = lis2mdl_magnetic_raw_get(ctx, raw_mag);
261 if (rc) {
262 LOG_ERR("Failed to read sample");
263 return rc;
264 }
265 lis2mdl->mag[0] = sys_le16_to_cpu(raw_mag[0]);
266 lis2mdl->mag[1] = sys_le16_to_cpu(raw_mag[1]);
267 lis2mdl->mag[2] = sys_le16_to_cpu(raw_mag[2]);
268 }
269 return 0;
270 }
271
lis2mdl_sample_fetch_temp(const struct device * dev)272 static int lis2mdl_sample_fetch_temp(const struct device *dev)
273 {
274 struct lis2mdl_data *lis2mdl = dev->data;
275 const struct lis2mdl_config *cfg = dev->config;
276 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
277 int16_t raw_temp;
278
279 /* fetch raw temperature sample */
280 if (lis2mdl_temperature_raw_get(ctx, &raw_temp) < 0) {
281 LOG_ERR("Failed to read sample");
282 return -EIO;
283 }
284
285 lis2mdl->temp_sample = (sys_le16_to_cpu(raw_temp));
286
287 return 0;
288 }
289
lis2mdl_sample_fetch(const struct device * dev,enum sensor_channel chan)290 static int lis2mdl_sample_fetch(const struct device *dev,
291 enum sensor_channel chan)
292 {
293 switch (chan) {
294 case SENSOR_CHAN_MAGN_X:
295 case SENSOR_CHAN_MAGN_Y:
296 case SENSOR_CHAN_MAGN_Z:
297 case SENSOR_CHAN_MAGN_XYZ:
298 lis2mdl_sample_fetch_mag(dev);
299 break;
300 case SENSOR_CHAN_DIE_TEMP:
301 lis2mdl_sample_fetch_temp(dev);
302 break;
303 case SENSOR_CHAN_ALL:
304 lis2mdl_sample_fetch_mag(dev);
305 lis2mdl_sample_fetch_temp(dev);
306 break;
307 default:
308 return -ENOTSUP;
309 }
310
311 return 0;
312 }
313
314 static const struct sensor_driver_api lis2mdl_driver_api = {
315 .attr_set = lis2mdl_attr_set,
316 #if CONFIG_LIS2MDL_TRIGGER
317 .trigger_set = lis2mdl_trigger_set,
318 #endif
319 .sample_fetch = lis2mdl_sample_fetch,
320 .channel_get = lis2mdl_channel_get,
321 };
322
lis2mdl_init(const struct device * dev)323 static int lis2mdl_init(const struct device *dev)
324 {
325 struct lis2mdl_data *lis2mdl = dev->data;
326 const struct lis2mdl_config *cfg = dev->config;
327 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
328 uint8_t wai;
329 int rc = 0;
330
331 lis2mdl->dev = dev;
332
333 if (cfg->spi_4wires) {
334 /* Set SPI 4wires if it's the case */
335 if (lis2mdl_spi_mode_set(ctx, LIS2MDL_SPI_4_WIRE) < 0) {
336 return -EIO;
337 }
338 }
339
340 /* check chip ID */
341 if (lis2mdl_device_id_get(ctx, &wai) < 0) {
342 return -EIO;
343 }
344
345 if (wai != LIS2MDL_ID) {
346 LOG_ERR("Invalid chip ID: %02x", wai);
347 return -EINVAL;
348 }
349
350 /* reset sensor configuration */
351 if (lis2mdl_reset_set(ctx, PROPERTY_ENABLE) < 0) {
352 LOG_ERR("s/w reset failed");
353 return -EIO;
354 }
355
356 k_busy_wait(100);
357
358 if (cfg->spi_4wires) {
359 /* After s/w reset set SPI 4wires again if the case */
360 if (lis2mdl_spi_mode_set(ctx, LIS2MDL_SPI_4_WIRE) < 0) {
361 return -EIO;
362 }
363 }
364
365 /* enable BDU */
366 if (lis2mdl_block_data_update_set(ctx, PROPERTY_ENABLE) < 0) {
367 LOG_ERR("setting bdu failed");
368 return -EIO;
369 }
370
371 /* Set Output Data Rate */
372 if (lis2mdl_data_rate_set(ctx, LIS2MDL_ODR_10Hz)) {
373 LOG_ERR("set odr failed");
374 return -EIO;
375 }
376
377 if (cfg->cancel_offset) {
378 /* Set offset cancellation, common for both single and
379 * and continuous mode.
380 */
381 if (lis2mdl_set_rst_mode_set(ctx,
382 LIS2MDL_SENS_OFF_CANC_EVERY_ODR)) {
383 LOG_ERR("reset sensor mode failed");
384 return -EIO;
385 }
386 }
387
388 /* Enable temperature compensation */
389 if (lis2mdl_offset_temp_comp_set(ctx, PROPERTY_ENABLE)) {
390 LOG_ERR("enable temp compensation failed");
391 return -EIO;
392 }
393
394 if (cfg->cancel_offset && cfg->single_mode) {
395 /* Set OFF_CANC_ONE_SHOT bit. This setting is only needed in
396 * the single-mode when offset cancellation is enabled.
397 */
398 rc = lis2mdl_set_rst_sensor_single_set(ctx,
399 PROPERTY_ENABLE);
400 if (rc) {
401 LOG_ERR("Set offset cancellation failed");
402 return rc;
403 }
404 }
405
406 if (cfg->single_mode) {
407 /* Set drdy on pin 7 */
408 rc = lis2mdl_drdy_on_pin_set(ctx, 1);
409 if (rc) {
410 LOG_ERR("set drdy on pin failed!");
411 return rc;
412 }
413
414 /* Reboot sensor after setting the configuration registers */
415 rc = lis2mdl_boot_set(ctx, 1);
416 if (rc) {
417 LOG_ERR("Reboot failed.");
418 return rc;
419 }
420
421 k_sem_init(&lis2mdl->fetch_sem, 0, 1);
422
423 } else {
424 /* Set device in continuous mode */
425 rc = lis2mdl_operating_mode_set(ctx,
426 LIS2MDL_CONTINUOUS_MODE);
427 if (rc) {
428 LOG_ERR("set continuous mode failed");
429 return rc;
430 }
431 }
432
433 #ifdef CONFIG_LIS2MDL_TRIGGER
434 if (cfg->trig_enabled) {
435 if (lis2mdl_init_interrupt(dev) < 0) {
436 LOG_ERR("Failed to initialize interrupts");
437 return -EIO;
438 }
439 }
440 #endif
441
442 return 0;
443 }
444
445 #ifdef CONFIG_PM_DEVICE
lis2mdl_pm_action(const struct device * dev,enum pm_device_action action)446 static int lis2mdl_pm_action(const struct device *dev,
447 enum pm_device_action action)
448 {
449 const struct lis2mdl_config *config = dev->config;
450 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&config->ctx;
451 int status = 0;
452
453 switch (action) {
454 case PM_DEVICE_ACTION_RESUME:
455 if (config->single_mode) {
456 status = lis2mdl_operating_mode_set(ctx,
457 LIS2MDL_SINGLE_TRIGGER);
458 } else {
459 status = lis2mdl_operating_mode_set(ctx,
460 LIS2MDL_CONTINUOUS_MODE);
461 }
462 if (status) {
463 LOG_ERR("Power up failed");
464 }
465 LOG_DBG("State changed to active");
466 break;
467 case PM_DEVICE_ACTION_SUSPEND:
468 status = lis2mdl_operating_mode_set(ctx, LIS2MDL_POWER_DOWN);
469 if (status) {
470 LOG_ERR("Power down failed");
471 }
472 LOG_DBG("State changed to inactive");
473 break;
474 default:
475 return -ENOTSUP;
476 }
477
478 return status;
479 }
480 #endif /* CONFIG_PM_DEVICE */
481
482 #if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
483 #warning "LIS2MDL driver enabled without any devices"
484 #endif
485
486 /*
487 * Device creation macro, shared by LIS2MDL_DEFINE_SPI() and
488 * LIS2MDL_DEFINE_I2C().
489 */
490
491 #define LIS2MDL_DEVICE_INIT(inst) \
492 PM_DEVICE_DT_INST_DEFINE(inst, lis2mdl_pm_action); \
493 \
494 SENSOR_DEVICE_DT_INST_DEFINE(inst, \
495 lis2mdl_init, \
496 PM_DEVICE_DT_INST_GET(inst), \
497 &lis2mdl_data_##inst, \
498 &lis2mdl_config_##inst, \
499 POST_KERNEL, \
500 CONFIG_SENSOR_INIT_PRIORITY, \
501 &lis2mdl_driver_api);
502
503 /*
504 * Instantiation macros used when a device is on a SPI bus.
505 */
506
507 #ifdef CONFIG_LIS2MDL_TRIGGER
508 #define LIS2MDL_CFG_IRQ(inst) \
509 .trig_enabled = true, \
510 .gpio_drdy = GPIO_DT_SPEC_INST_GET(inst, irq_gpios)
511 #else
512 #define LIS2MDL_CFG_IRQ(inst)
513 #endif /* CONFIG_LIS2MDL_TRIGGER */
514
515 #define LIS2MDL_CONFIG_COMMON(inst) \
516 .cancel_offset = DT_INST_PROP(inst, cancel_offset), \
517 .single_mode = DT_INST_PROP(inst, single_mode), \
518 COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \
519 (LIS2MDL_CFG_IRQ(inst)), ())
520
521 #define LIS2MDL_SPI_OPERATION (SPI_WORD_SET(8) | \
522 SPI_OP_MODE_MASTER | \
523 SPI_MODE_CPOL | \
524 SPI_MODE_CPHA) \
525
526 #define LIS2MDL_CONFIG_SPI(inst) \
527 { \
528 STMEMSC_CTX_SPI(&lis2mdl_config_##inst.stmemsc_cfg), \
529 .stmemsc_cfg = { \
530 .spi = SPI_DT_SPEC_INST_GET(inst, \
531 LIS2MDL_SPI_OPERATION, \
532 0), \
533 }, \
534 .spi_4wires = DT_INST_PROP(inst, spi_full_duplex), \
535 LIS2MDL_CONFIG_COMMON(inst) \
536 }
537
538 /*
539 * Instantiation macros used when a device is on an I2C bus.
540 */
541
542 #define LIS2MDL_CONFIG_I2C(inst) \
543 { \
544 STMEMSC_CTX_I2C(&lis2mdl_config_##inst.stmemsc_cfg), \
545 .stmemsc_cfg = { \
546 .i2c = I2C_DT_SPEC_INST_GET(inst), \
547 }, \
548 LIS2MDL_CONFIG_COMMON(inst) \
549 }
550
551 /*
552 * Main instantiation macro. Use of COND_CODE_1() selects the right
553 * bus-specific macro at preprocessor time.
554 */
555
556 #define LIS2MDL_DEFINE(inst) \
557 static struct lis2mdl_data lis2mdl_data_##inst; \
558 static const struct lis2mdl_config lis2mdl_config_##inst = \
559 COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
560 (LIS2MDL_CONFIG_SPI(inst)), \
561 (LIS2MDL_CONFIG_I2C(inst))); \
562 LIS2MDL_DEVICE_INIT(inst)
563
564 DT_INST_FOREACH_STATUS_OKAY(LIS2MDL_DEFINE)
565