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