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