1 /* ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver
2  *
3  * Copyright (c) 2023 STMicroelectronics
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  *
7  * Datasheet:
8  * https://www.st.com/resource/en/datasheet/lis2du12.pdf
9  */
10 
11 #define DT_DRV_COMPAT st_lis2du12
12 
13 #include <zephyr/drivers/sensor.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/device.h>
16 #include <zephyr/init.h>
17 #include <string.h>
18 #include <zephyr/sys/byteorder.h>
19 #include <zephyr/sys/__assert.h>
20 #include <zephyr/logging/log.h>
21 
22 #include "lis2du12.h"
23 
24 LOG_MODULE_REGISTER(LIS2DU12, CONFIG_SENSOR_LOG_LEVEL);
25 
26 static const float lis2du12_odr_map[14] = {
27 			0.0f, 1.6f, 3.0f, 6.0f, 6.0f, 12.5f, 25.0f,
28 			50.0f, 100.0f, 200.0f, 400.0f, 800.0f, 0.0f, 0.0f};
29 
lis2du12_freq_to_odr_val(const struct device * dev,uint16_t freq)30 static int lis2du12_freq_to_odr_val(const struct device *dev, uint16_t freq)
31 {
32 	size_t i;
33 
34 	for (i = 0; i < ARRAY_SIZE(lis2du12_odr_map); i++) {
35 		if (freq <= lis2du12_odr_map[i]) {
36 			return i;
37 		}
38 	}
39 
40 	return -EINVAL;
41 }
42 
43 static const uint16_t lis2du12_accel_fs_map[] = {2, 4, 8, 16};
44 
lis2du12_accel_range_to_fs_val(int32_t range)45 static int lis2du12_accel_range_to_fs_val(int32_t range)
46 {
47 	size_t i;
48 
49 	for (i = 0; i < ARRAY_SIZE(lis2du12_accel_fs_map); i++) {
50 		if (range == lis2du12_accel_fs_map[i]) {
51 			return i;
52 		}
53 	}
54 
55 	return -EINVAL;
56 }
57 
lis2du12_reboot(const struct device * dev)58 static inline int lis2du12_reboot(const struct device *dev)
59 {
60 	const struct lis2du12_config *cfg = dev->config;
61 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
62 	lis2du12_status_t status;
63 	uint8_t tries = 10;
64 
65 	if (lis2du12_init_set(ctx, LIS2DU12_RESET) < 0) {
66 		return -EIO;
67 	}
68 
69 	do {
70 		if (!--tries) {
71 			LOG_ERR("sw reset timed out");
72 			return -ETIMEDOUT;
73 		}
74 		k_usleep(50);
75 
76 		if (lis2du12_status_get(ctx, &status) < 0) {
77 			return -EIO;
78 		}
79 	} while (status.sw_reset != 0);
80 
81 	if (lis2du12_init_set(ctx, LIS2DU12_DRV_RDY) < 0) {
82 		return -EIO;
83 	}
84 
85 	return 0;
86 }
87 
lis2du12_accel_set_fs_raw(const struct device * dev,uint8_t fs)88 static int lis2du12_accel_set_fs_raw(const struct device *dev, uint8_t fs)
89 {
90 	const struct lis2du12_config *cfg = dev->config;
91 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
92 	struct lis2du12_data *data = dev->data;
93 	lis2du12_md_t mode;
94 
95 	if (lis2du12_mode_get(ctx, &mode) < 0) {
96 		return -EIO;
97 	}
98 
99 	mode.fs = fs;
100 	if (lis2du12_mode_set(ctx, &mode) < 0) {
101 		return -EIO;
102 	}
103 
104 	data->accel_fs = fs;
105 
106 	return 0;
107 }
108 
lis2du12_accel_set_odr_raw(const struct device * dev,uint8_t odr)109 static int lis2du12_accel_set_odr_raw(const struct device *dev, uint8_t odr)
110 {
111 	const struct lis2du12_config *cfg = dev->config;
112 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
113 	struct lis2du12_data *data = dev->data;
114 	lis2du12_md_t mode;
115 
116 	if (lis2du12_mode_get(ctx, &mode) < 0) {
117 		return -EIO;
118 	}
119 
120 	mode.odr = odr;
121 	if (lis2du12_mode_set(ctx, &mode) < 0) {
122 		return -EIO;
123 	}
124 
125 	data->accel_freq = odr;
126 
127 	return 0;
128 }
129 
lis2du12_accel_odr_set(const struct device * dev,uint16_t freq)130 static int lis2du12_accel_odr_set(const struct device *dev, uint16_t freq)
131 {
132 	int odr;
133 
134 	odr = lis2du12_freq_to_odr_val(dev, freq);
135 	if (odr < 0) {
136 		return odr;
137 	}
138 
139 	if (lis2du12_accel_set_odr_raw(dev, odr) < 0) {
140 		LOG_ERR("failed to set accelerometer sampling rate");
141 		return -EIO;
142 	}
143 
144 	return 0;
145 }
146 
lis2du12_accel_range_set(const struct device * dev,int32_t range)147 static int lis2du12_accel_range_set(const struct device *dev, int32_t range)
148 {
149 	int fs;
150 	struct lis2du12_data *data = dev->data;
151 
152 	fs = lis2du12_accel_range_to_fs_val(range);
153 	if (fs < 0) {
154 		return fs;
155 	}
156 
157 	if (lis2du12_accel_set_fs_raw(dev, fs) < 0) {
158 		LOG_ERR("failed to set accelerometer full-scale");
159 		return -EIO;
160 	}
161 
162 	data->acc_gain = lis2du12_accel_fs_map[fs] * GAIN_UNIT_XL / 2;
163 	return 0;
164 }
165 
lis2du12_accel_config(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)166 static int lis2du12_accel_config(const struct device *dev,
167 				 enum sensor_channel chan,
168 				 enum sensor_attribute attr,
169 				 const struct sensor_value *val)
170 {
171 	switch (attr) {
172 	case SENSOR_ATTR_FULL_SCALE:
173 		return lis2du12_accel_range_set(dev, sensor_ms2_to_g(val));
174 	case SENSOR_ATTR_SAMPLING_FREQUENCY:
175 		return lis2du12_accel_odr_set(dev, val->val1);
176 	default:
177 		LOG_WRN("Accel attribute %d not supported.", attr);
178 		return -ENOTSUP;
179 	}
180 
181 	return 0;
182 }
183 
lis2du12_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)184 static int lis2du12_attr_set(const struct device *dev,
185 			     enum sensor_channel chan,
186 			     enum sensor_attribute attr,
187 			     const struct sensor_value *val)
188 {
189 	switch (chan) {
190 	case SENSOR_CHAN_ACCEL_XYZ:
191 		return lis2du12_accel_config(dev, chan, attr, val);
192 	default:
193 		LOG_WRN("attribute %d not supported on this channel.", chan);
194 		return -ENOTSUP;
195 	}
196 
197 	return 0;
198 }
199 
lis2du12_sample_fetch_accel(const struct device * dev)200 static int lis2du12_sample_fetch_accel(const struct device *dev)
201 {
202 	const struct lis2du12_config *cfg = dev->config;
203 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
204 	struct lis2du12_data *data = dev->data;
205 	lis2du12_data_t xl_data;
206 	lis2du12_md_t md;
207 
208 	md.fs = cfg->accel_range;
209 	if (lis2du12_data_get(ctx, &md, &xl_data) < 0) {
210 		LOG_ERR("Failed to read sample");
211 		return -EIO;
212 	}
213 
214 	data->acc[0] = xl_data.xl.raw[0];
215 	data->acc[1] = xl_data.xl.raw[1];
216 	data->acc[2] = xl_data.xl.raw[2];
217 
218 	return 0;
219 }
220 
lis2du12_sample_fetch(const struct device * dev,enum sensor_channel chan)221 static int lis2du12_sample_fetch(const struct device *dev,
222 				 enum sensor_channel chan)
223 {
224 	switch (chan) {
225 	case SENSOR_CHAN_ACCEL_XYZ:
226 		lis2du12_sample_fetch_accel(dev);
227 		break;
228 	case SENSOR_CHAN_ALL:
229 		lis2du12_sample_fetch_accel(dev);
230 		break;
231 	default:
232 		return -ENOTSUP;
233 	}
234 
235 	return 0;
236 }
237 
lis2du12_accel_convert(struct sensor_value * val,int raw_val,uint32_t sensitivity)238 static inline void lis2du12_accel_convert(struct sensor_value *val, int raw_val,
239 					  uint32_t sensitivity)
240 {
241 	int64_t dval;
242 
243 	/* Sensitivity is exposed in ug/LSB */
244 	/* Convert to m/s^2 */
245 	dval = (int64_t)(raw_val) * sensitivity * SENSOR_G_DOUBLE;
246 	val->val1 = (int32_t)(dval / 1000000);
247 	val->val2 = (int32_t)(dval % 1000000);
248 
249 }
250 
lis2du12_accel_get_channel(enum sensor_channel chan,struct sensor_value * val,struct lis2du12_data * data,uint32_t sensitivity)251 static inline int lis2du12_accel_get_channel(enum sensor_channel chan,
252 					     struct sensor_value *val,
253 					     struct lis2du12_data *data,
254 					     uint32_t sensitivity)
255 {
256 	uint8_t i;
257 
258 	switch (chan) {
259 	case SENSOR_CHAN_ACCEL_X:
260 		lis2du12_accel_convert(val, data->acc[0], sensitivity);
261 		break;
262 	case SENSOR_CHAN_ACCEL_Y:
263 		lis2du12_accel_convert(val, data->acc[1], sensitivity);
264 		break;
265 	case SENSOR_CHAN_ACCEL_Z:
266 		lis2du12_accel_convert(val, data->acc[2], sensitivity);
267 		break;
268 	case SENSOR_CHAN_ACCEL_XYZ:
269 		for (i = 0; i < 3; i++) {
270 			lis2du12_accel_convert(val++, data->acc[i], sensitivity);
271 		}
272 		break;
273 	default:
274 		return -ENOTSUP;
275 	}
276 
277 	return 0;
278 }
279 
lis2du12_accel_channel_get(enum sensor_channel chan,struct sensor_value * val,struct lis2du12_data * data)280 static int lis2du12_accel_channel_get(enum sensor_channel chan,
281 				      struct sensor_value *val,
282 				      struct lis2du12_data *data)
283 {
284 	return lis2du12_accel_get_channel(chan, val, data, data->acc_gain);
285 }
286 
lis2du12_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)287 static int lis2du12_channel_get(const struct device *dev,
288 				enum sensor_channel chan,
289 				struct sensor_value *val)
290 {
291 	struct lis2du12_data *data = dev->data;
292 
293 	switch (chan) {
294 	case SENSOR_CHAN_ACCEL_X:
295 	case SENSOR_CHAN_ACCEL_Y:
296 	case SENSOR_CHAN_ACCEL_Z:
297 	case SENSOR_CHAN_ACCEL_XYZ:
298 		lis2du12_accel_channel_get(chan, val, data);
299 		break;
300 	default:
301 		return -ENOTSUP;
302 	}
303 
304 	return 0;
305 }
306 
307 static DEVICE_API(sensor, lis2du12_driver_api) = {
308 	.attr_set = lis2du12_attr_set,
309 #if CONFIG_LIS2DU12_TRIGGER
310 	.trigger_set = lis2du12_trigger_set,
311 #endif
312 	.sample_fetch = lis2du12_sample_fetch,
313 	.channel_get = lis2du12_channel_get,
314 };
315 
lis2du12_init_chip(const struct device * dev)316 static int lis2du12_init_chip(const struct device *dev)
317 {
318 	const struct lis2du12_config *cfg = dev->config;
319 	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
320 	struct lis2du12_data *lis2du12 = dev->data;
321 	lis2du12_id_t chip_id;
322 	uint8_t odr, fs;
323 
324 	if (lis2du12_id_get(ctx, &chip_id) < 0) {
325 		LOG_ERR("Failed reading chip id");
326 		return -EIO;
327 	}
328 
329 	LOG_INF("chip id 0x%x", chip_id.whoami);
330 
331 	if (chip_id.whoami != LIS2DU12_ID) {
332 		LOG_ERR("Invalid chip id 0x%x", chip_id.whoami);
333 		return -EIO;
334 	}
335 
336 	/* reboot device */
337 	if (lis2du12_reboot(dev) < 0) {
338 		return -EIO;
339 	}
340 
341 	/* set FS from DT */
342 	fs = cfg->accel_range;
343 	LOG_DBG("accel range is %d", fs);
344 	if (lis2du12_accel_set_fs_raw(dev, fs) < 0) {
345 		LOG_ERR("failed to set accelerometer range %d", fs);
346 		return -EIO;
347 	}
348 	lis2du12->acc_gain = lis2du12_accel_fs_map[fs] * GAIN_UNIT_XL / 2;
349 
350 	/* set odr from DT (the only way to go in high performance) */
351 	odr = cfg->accel_odr;
352 	LOG_DBG("accel odr is %d", odr);
353 	if (lis2du12_accel_set_odr_raw(dev, odr) < 0) {
354 		LOG_ERR("failed to set accelerometer odr %d", odr);
355 		return -EIO;
356 	}
357 
358 	return 0;
359 }
360 
lis2du12_init(const struct device * dev)361 static int lis2du12_init(const struct device *dev)
362 {
363 #ifdef CONFIG_LIS2DU12_TRIGGER
364 	const struct lis2du12_config *cfg = dev->config;
365 #endif
366 	struct lis2du12_data *data = dev->data;
367 
368 	LOG_INF("Initialize device %s", dev->name);
369 	data->dev = dev;
370 
371 	if (lis2du12_init_chip(dev) < 0) {
372 		LOG_ERR("failed to initialize chip");
373 		return -EIO;
374 	}
375 
376 #ifdef CONFIG_LIS2DU12_TRIGGER
377 	if (cfg->trig_enabled) {
378 		if (lis2du12_init_interrupt(dev) < 0) {
379 			LOG_ERR("Failed to initialize interrupt.");
380 			return -EIO;
381 		}
382 	}
383 #endif
384 
385 	return 0;
386 }
387 
388 /*
389  * Device creation macro, shared by LIS2DU12_DEFINE_SPI() and
390  * LIS2DU12_DEFINE_I2C().
391  */
392 
393 #define LIS2DU12_DEVICE_INIT(inst)					\
394 	SENSOR_DEVICE_DT_INST_DEFINE(inst,				\
395 			    lis2du12_init,				\
396 			    NULL,					\
397 			    &lis2du12_data_##inst,			\
398 			    &lis2du12_config_##inst,			\
399 			    POST_KERNEL,				\
400 			    CONFIG_SENSOR_INIT_PRIORITY,		\
401 			    &lis2du12_driver_api);
402 
403 /*
404  * Instantiation macros used when a device is on a SPI bus.
405  */
406 
407 #ifdef CONFIG_LIS2DU12_TRIGGER
408 #define LIS2DU12_CFG_IRQ(inst)						\
409 	.trig_enabled = true,						\
410 	.int1_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int1_gpios, { 0 }), \
411 	.int2_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int2_gpios, { 0 }), \
412 	.drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed),			\
413 	.drdy_pin = DT_INST_PROP(inst, drdy_pin)
414 #else
415 #define LIS2DU12_CFG_IRQ(inst)
416 #endif /* CONFIG_LIS2DU12_TRIGGER */
417 
418 #define LIS2DU12_SPI_OP  (SPI_WORD_SET(8) |				\
419 			 SPI_OP_MODE_MASTER |				\
420 			 SPI_MODE_CPOL |				\
421 			 SPI_MODE_CPHA)					\
422 
423 #define LIS2DU12_CONFIG_COMMON(inst)					\
424 	.accel_odr = DT_INST_PROP(inst, accel_odr),			\
425 	.accel_range = DT_INST_PROP(inst, accel_range),			\
426 	IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios),	\
427 			   DT_INST_NODE_HAS_PROP(inst, int2_gpios)),	\
428 		   (LIS2DU12_CFG_IRQ(inst)))
429 
430 /*
431  * Instantiation macros used when a device is on a SPI bus.
432  */
433 
434 #define LIS2DU12_CONFIG_SPI(inst)						\
435 	{									\
436 		STMEMSC_CTX_SPI(&lis2du12_config_##inst.stmemsc_cfg),		\
437 		.stmemsc_cfg = {						\
438 			.spi = SPI_DT_SPEC_INST_GET(inst,			\
439 					   LIS2DU12_SPI_OP,			\
440 					   0),					\
441 		},								\
442 		LIS2DU12_CONFIG_COMMON(inst)					\
443 	}
444 
445 /*
446  * Instantiation macros used when a device is on an I2C bus.
447  */
448 
449 #define LIS2DU12_CONFIG_I2C(inst)						\
450 	{									\
451 		STMEMSC_CTX_I2C(&lis2du12_config_##inst.stmemsc_cfg),	\
452 		.stmemsc_cfg = {						\
453 			.i2c = I2C_DT_SPEC_INST_GET(inst),			\
454 		},								\
455 		LIS2DU12_CONFIG_COMMON(inst)					\
456 	}
457 
458 /*
459  * Main instantiation macro. Use of COND_CODE_1() selects the right
460  * bus-specific macro at preprocessor time.
461  */
462 
463 #define LIS2DU12_DEFINE(inst)						\
464 	static struct lis2du12_data lis2du12_data_##inst;			\
465 	static const struct lis2du12_config lis2du12_config_##inst =	\
466 		COND_CODE_1(DT_INST_ON_BUS(inst, spi),			\
467 			(LIS2DU12_CONFIG_SPI(inst)),			\
468 			(LIS2DU12_CONFIG_I2C(inst)));			\
469 	LIS2DU12_DEVICE_INIT(inst)
470 
471 DT_INST_FOREACH_STATUS_OKAY(LIS2DU12_DEFINE)
472