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