1 /* ST Microelectronics LSM6DSO 6-axis IMU sensor driver
2 *
3 * Copyright (c) 2019 STMicroelectronics
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Datasheet:
8 * https://www.st.com/resource/en/datasheet/lsm6dso.pdf
9 */
10
11 #define DT_DRV_COMPAT st_lsm6dso
12
13 #include <zephyr/device.h>
14 #include <zephyr/drivers/i2c.h>
15 #include <zephyr/sys/__assert.h>
16 #include <zephyr/sys/util.h>
17 #include <zephyr/kernel.h>
18 #include <zephyr/drivers/sensor.h>
19 #include <zephyr/logging/log.h>
20
21 #include "lsm6dso.h"
22
23 LOG_MODULE_DECLARE(LSM6DSO, CONFIG_SENSOR_LOG_LEVEL);
24
25 static int lsm6dso_shub_write_target_reg(const struct device *dev,
26 uint8_t trgt_addr, uint8_t trgt_reg,
27 uint8_t *value, uint16_t len);
28 static int lsm6dso_shub_read_target_reg(const struct device *dev,
29 uint8_t trgt_addr, uint8_t trgt_reg,
30 uint8_t *value, uint16_t len);
31 static void lsm6dso_shub_enable(const struct device *dev, uint8_t enable);
32
33
34 /* ST HAL skips this register, only supports it via the slower lsm6dso_sh_status_get() */
lsm6dso_sh_status_mainpage_get(stmdev_ctx_t * ctx,lsm6dso_status_master_t * val)35 static int32_t lsm6dso_sh_status_mainpage_get(stmdev_ctx_t *ctx, lsm6dso_status_master_t *val)
36 {
37 return lsm6dso_read_reg(ctx, LSM6DSO_STATUS_MASTER_MAINPAGE, (uint8_t *)val, 1);
38 }
39
40 /*
41 * LIS2MDL magn device specific part
42 */
43 #ifdef CONFIG_LSM6DSO_EXT_LIS2MDL
44
45 #define LIS2MDL_CFG_REG_A 0x60
46 #define LIS2MDL_CFG_REG_B 0x61
47 #define LIS2MDL_CFG_REG_C 0x62
48 #define LIS2MDL_STATUS_REG 0x67
49
50 #define LIS2MDL_SW_RESET 0x20
51 #define LIS2MDL_ODR_10HZ 0x00
52 #define LIS2MDL_ODR_100HZ 0x0C
53 #define LIS2MDL_OFF_CANC 0x02
54 #define LIS2MDL_SENSITIVITY 1500
55
lsm6dso_lis2mdl_init(const struct device * dev,uint8_t i2c_addr)56 static int lsm6dso_lis2mdl_init(const struct device *dev, uint8_t i2c_addr)
57 {
58 struct lsm6dso_data *data = dev->data;
59 uint8_t mag_cfg[2];
60
61 data->magn_gain = LIS2MDL_SENSITIVITY;
62
63 /* sw reset device */
64 mag_cfg[0] = LIS2MDL_SW_RESET;
65 lsm6dso_shub_write_target_reg(dev, i2c_addr,
66 LIS2MDL_CFG_REG_A, mag_cfg, 1);
67
68 k_sleep(K_MSEC(10)); /* turn-on time in ms */
69
70 /* configure mag */
71 mag_cfg[0] = LIS2MDL_ODR_10HZ;
72 mag_cfg[1] = LIS2MDL_OFF_CANC;
73 lsm6dso_shub_write_target_reg(dev, i2c_addr,
74 LIS2MDL_CFG_REG_A, mag_cfg, 2);
75
76 return 0;
77 }
78
79 static const uint16_t lis2mdl_map[] = {10, 20, 50, 100};
80
lsm6dso_lis2mdl_odr_set(const struct device * dev,uint8_t i2c_addr,uint16_t freq)81 static int lsm6dso_lis2mdl_odr_set(const struct device *dev,
82 uint8_t i2c_addr, uint16_t freq)
83 {
84 uint8_t odr, cfg;
85
86 for (odr = 0; odr < ARRAY_SIZE(lis2mdl_map); odr++) {
87 if (freq == lis2mdl_map[odr]) {
88 break;
89 }
90 }
91
92 if (odr == ARRAY_SIZE(lis2mdl_map)) {
93 LOG_DBG("shub: LIS2MDL freq val %d not supported.", freq);
94 return -ENOTSUP;
95 }
96
97 cfg = (odr << 2);
98 lsm6dso_shub_write_target_reg(dev, i2c_addr,
99 LIS2MDL_CFG_REG_A, &cfg, 1);
100
101 lsm6dso_shub_enable(dev, 1);
102 return 0;
103 }
104
lsm6dso_lis2mdl_conf(const struct device * dev,uint8_t i2c_addr,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)105 static int lsm6dso_lis2mdl_conf(const struct device *dev, uint8_t i2c_addr,
106 enum sensor_channel chan,
107 enum sensor_attribute attr,
108 const struct sensor_value *val)
109 {
110 switch (attr) {
111 case SENSOR_ATTR_SAMPLING_FREQUENCY:
112 return lsm6dso_lis2mdl_odr_set(dev, i2c_addr, val->val1);
113 default:
114 LOG_DBG("shub: LIS2MDL attribute not supported.");
115 return -ENOTSUP;
116 }
117
118 return 0;
119 }
120 #endif /* CONFIG_LSM6DSO_EXT_LIS2MDL */
121
122 /*
123 * HTS221 humidity device specific part
124 */
125 #ifdef CONFIG_LSM6DSO_EXT_HTS221
126
127 #define HTS221_AUTOINCREMENT BIT(7)
128
129 #define HTS221_REG_CTRL1 0x20
130 #define HTS221_ODR_1HZ 0x01
131 #define HTS221_BDU 0x04
132 #define HTS221_PD 0x80
133
134 #define HTS221_REG_CONV_START 0x30
135
lsm6dso_hts221_read_conv_data(const struct device * dev,uint8_t i2c_addr)136 static int lsm6dso_hts221_read_conv_data(const struct device *dev,
137 uint8_t i2c_addr)
138 {
139 struct lsm6dso_data *data = dev->data;
140 uint8_t buf[16], i;
141 struct hts221_data *ht = &data->hts221;
142
143 for (i = 0; i < sizeof(buf); i += 7) {
144 unsigned char len = MIN(7, sizeof(buf) - i);
145
146 if (lsm6dso_shub_read_target_reg(dev, i2c_addr,
147 (HTS221_REG_CONV_START + i) |
148 HTS221_AUTOINCREMENT,
149 &buf[i], len) < 0) {
150 LOG_DBG("shub: failed to read hts221 conv data");
151 return -EIO;
152 }
153 }
154
155 ht->y0 = buf[0] / 2;
156 ht->y1 = buf[1] / 2;
157 ht->x0 = buf[6] | (buf[7] << 8);
158 ht->x1 = buf[10] | (buf[11] << 8);
159
160 return 0;
161 }
162
lsm6dso_hts221_init(const struct device * dev,uint8_t i2c_addr)163 static int lsm6dso_hts221_init(const struct device *dev, uint8_t i2c_addr)
164 {
165 uint8_t hum_cfg;
166
167 /* configure ODR and BDU */
168 hum_cfg = HTS221_ODR_1HZ | HTS221_BDU | HTS221_PD;
169 lsm6dso_shub_write_target_reg(dev, i2c_addr,
170 HTS221_REG_CTRL1, &hum_cfg, 1);
171
172 return lsm6dso_hts221_read_conv_data(dev, i2c_addr);
173 }
174
175 static const uint16_t hts221_map[] = {0, 1, 7, 12};
176
lsm6dso_hts221_odr_set(const struct device * dev,uint8_t i2c_addr,uint16_t freq)177 static int lsm6dso_hts221_odr_set(const struct device *dev,
178 uint8_t i2c_addr, uint16_t freq)
179 {
180 uint8_t odr, cfg;
181
182 for (odr = 0; odr < ARRAY_SIZE(hts221_map); odr++) {
183 if (freq == hts221_map[odr]) {
184 break;
185 }
186 }
187
188 if (odr == ARRAY_SIZE(hts221_map)) {
189 LOG_DBG("shub: HTS221 freq val %d not supported.", freq);
190 return -ENOTSUP;
191 }
192
193 cfg = odr | HTS221_BDU | HTS221_PD;
194 lsm6dso_shub_write_target_reg(dev, i2c_addr,
195 HTS221_REG_CTRL1, &cfg, 1);
196
197 lsm6dso_shub_enable(dev, 1);
198 return 0;
199 }
200
lsm6dso_hts221_conf(const struct device * dev,uint8_t i2c_addr,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)201 static int lsm6dso_hts221_conf(const struct device *dev, uint8_t i2c_addr,
202 enum sensor_channel chan,
203 enum sensor_attribute attr,
204 const struct sensor_value *val)
205 {
206 switch (attr) {
207 case SENSOR_ATTR_SAMPLING_FREQUENCY:
208 return lsm6dso_hts221_odr_set(dev, i2c_addr, val->val1);
209 default:
210 LOG_DBG("shub: HTS221 attribute not supported.");
211 return -ENOTSUP;
212 }
213
214 return 0;
215 }
216 #endif /* CONFIG_LSM6DSO_EXT_HTS221 */
217
218 /*
219 * LPS22HB baro/temp device specific part
220 */
221 #ifdef CONFIG_LSM6DSO_EXT_LPS22HB
222
223 #define LPS22HB_CTRL_REG1 0x10
224 #define LPS22HB_CTRL_REG2 0x11
225
226 #define LPS22HB_SW_RESET 0x04
227 #define LPS22HB_ODR_10HZ 0x20
228 #define LPS22HB_LPF_EN 0x08
229 #define LPS22HB_BDU_EN 0x02
230
lsm6dso_lps22hb_init(const struct device * dev,uint8_t i2c_addr)231 static int lsm6dso_lps22hb_init(const struct device *dev, uint8_t i2c_addr)
232 {
233 uint8_t baro_cfg[2];
234
235 /* sw reset device */
236 baro_cfg[0] = LPS22HB_SW_RESET;
237 lsm6dso_shub_write_target_reg(dev, i2c_addr,
238 LPS22HB_CTRL_REG2, baro_cfg, 1);
239
240 k_sleep(K_MSEC(1)); /* turn-on time in ms */
241
242 /* configure device */
243 baro_cfg[0] = LPS22HB_ODR_10HZ | LPS22HB_LPF_EN | LPS22HB_BDU_EN;
244 lsm6dso_shub_write_target_reg(dev, i2c_addr,
245 LPS22HB_CTRL_REG1, baro_cfg, 1);
246
247 return 0;
248 }
249 #endif /* CONFIG_LSM6DSO_EXT_LPS22HB */
250
251 /*
252 * LPS22HH baro/temp device specific part
253 */
254 #ifdef CONFIG_LSM6DSO_EXT_LPS22HH
255
256 #define LPS22HH_CTRL_REG1 0x10
257 #define LPS22HH_CTRL_REG2 0x11
258
259 #define LPS22HH_SW_RESET 0x04
260 #define LPS22HH_IF_ADD_INC 0x10
261 #define LPS22HH_ODR_10HZ 0x20
262 #define LPS22HH_LPF_EN 0x08
263 #define LPS22HH_BDU_EN 0x02
264
lsm6dso_lps22hh_init(const struct device * dev,uint8_t i2c_addr)265 static int lsm6dso_lps22hh_init(const struct device *dev, uint8_t i2c_addr)
266 {
267 uint8_t baro_cfg[2];
268
269 /* sw reset device */
270 baro_cfg[0] = LPS22HH_SW_RESET;
271 lsm6dso_shub_write_target_reg(dev, i2c_addr,
272 LPS22HH_CTRL_REG2, baro_cfg, 1);
273
274 k_sleep(K_MSEC(100)); /* turn-on time in ms */
275
276 /* configure device */
277 baro_cfg[0] = LPS22HH_IF_ADD_INC;
278 lsm6dso_shub_write_target_reg(dev, i2c_addr,
279 LPS22HH_CTRL_REG2, baro_cfg, 1);
280
281 baro_cfg[0] = LPS22HH_ODR_10HZ | LPS22HH_LPF_EN | LPS22HH_BDU_EN;
282 lsm6dso_shub_write_target_reg(dev, i2c_addr,
283 LPS22HH_CTRL_REG1, baro_cfg, 1);
284
285 return 0;
286 }
287
288 static const uint16_t lps22hh_map[] = {0, 1, 10, 25, 50, 75, 100, 200};
289
lsm6dso_lps22hh_odr_set(const struct device * dev,uint8_t i2c_addr,uint16_t freq)290 static int lsm6dso_lps22hh_odr_set(const struct device *dev,
291 uint8_t i2c_addr, uint16_t freq)
292 {
293 uint8_t odr, cfg;
294
295 for (odr = 0; odr < ARRAY_SIZE(lps22hh_map); odr++) {
296 if (freq == lps22hh_map[odr]) {
297 break;
298 }
299 }
300
301 if (odr == ARRAY_SIZE(lps22hh_map)) {
302 LOG_DBG("shub: LPS22HH freq val %d not supported.", freq);
303 return -ENOTSUP;
304 }
305
306 cfg = (odr << 4) | LPS22HH_LPF_EN | LPS22HH_BDU_EN;
307 lsm6dso_shub_write_target_reg(dev, i2c_addr,
308 LPS22HH_CTRL_REG1, &cfg, 1);
309
310 lsm6dso_shub_enable(dev, 1);
311 return 0;
312 }
313
lsm6dso_lps22hh_conf(const struct device * dev,uint8_t i2c_addr,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)314 static int lsm6dso_lps22hh_conf(const struct device *dev, uint8_t i2c_addr,
315 enum sensor_channel chan,
316 enum sensor_attribute attr,
317 const struct sensor_value *val)
318 {
319 switch (attr) {
320 case SENSOR_ATTR_SAMPLING_FREQUENCY:
321 return lsm6dso_lps22hh_odr_set(dev, i2c_addr, val->val1);
322 default:
323 LOG_DBG("shub: LPS22HH attribute not supported.");
324 return -ENOTSUP;
325 }
326
327 return 0;
328 }
329 #endif /* CONFIG_LSM6DSO_EXT_LPS22HH */
330
331 /* List of supported external sensors */
332 static struct lsm6dso_shub_slist {
333 enum sensor_channel type;
334 uint8_t i2c_addr[2];
335 uint8_t ext_i2c_addr;
336 uint8_t wai_addr;
337 uint8_t wai_val;
338 uint8_t out_data_addr;
339 uint8_t out_data_len;
340 uint8_t sh_out_reg;
341 int (*dev_init)(const struct device *dev, uint8_t i2c_addr);
342 int (*dev_conf)(const struct device *dev, uint8_t i2c_addr,
343 enum sensor_channel chan, enum sensor_attribute attr,
344 const struct sensor_value *val);
345 } lsm6dso_shub_slist[] = {
346 #ifdef CONFIG_LSM6DSO_EXT_LIS2MDL
347 {
348 /* LIS2MDL */
349 .type = SENSOR_CHAN_MAGN_XYZ,
350 .i2c_addr = { 0x1E },
351 .wai_addr = 0x4F,
352 .wai_val = 0x40,
353 .out_data_addr = 0x68,
354 .out_data_len = 0x06,
355 .dev_init = (lsm6dso_lis2mdl_init),
356 .dev_conf = (lsm6dso_lis2mdl_conf),
357 },
358 #endif /* CONFIG_LSM6DSO_EXT_LIS2MDL */
359
360 #ifdef CONFIG_LSM6DSO_EXT_HTS221
361 {
362 /* HTS221 */
363 .type = SENSOR_CHAN_HUMIDITY,
364 .i2c_addr = { 0x5F },
365 .wai_addr = 0x0F,
366 .wai_val = 0xBC,
367 .out_data_addr = 0x28 | HTS221_AUTOINCREMENT,
368 .out_data_len = 0x02,
369 .dev_init = (lsm6dso_hts221_init),
370 .dev_conf = (lsm6dso_hts221_conf),
371 },
372 #endif /* CONFIG_LSM6DSO_EXT_HTS221 */
373
374 #ifdef CONFIG_LSM6DSO_EXT_LPS22HB
375 {
376 /* LPS22HB */
377 .type = SENSOR_CHAN_PRESS,
378 .i2c_addr = { 0x5C, 0x5D },
379 .wai_addr = 0x0F,
380 .wai_val = 0xB1,
381 .out_data_addr = 0x28,
382 .out_data_len = 0x05,
383 .dev_init = (lsm6dso_lps22hb_init),
384 },
385 #endif /* CONFIG_LSM6DSO_EXT_LPS22HB */
386
387 #ifdef CONFIG_LSM6DSO_EXT_LPS22HH
388 {
389 /* LPS22HH */
390 .type = SENSOR_CHAN_PRESS,
391 .i2c_addr = { 0x5C, 0x5D },
392 .wai_addr = 0x0F,
393 .wai_val = 0xB3,
394 .out_data_addr = 0x28,
395 .out_data_len = 0x05,
396 .dev_init = (lsm6dso_lps22hh_init),
397 .dev_conf = (lsm6dso_lps22hh_conf),
398 },
399 #endif /* CONFIG_LSM6DSO_EXT_LPS22HH */
400 };
401
lsm6dso_shub_wait_completed(stmdev_ctx_t * ctx)402 static int lsm6dso_shub_wait_completed(stmdev_ctx_t *ctx)
403 {
404 lsm6dso_status_master_t status;
405 int tries = 200; /* Should be max ~160 ms, from 2 cycles at slowest ODR 12.5 Hz */
406
407 do {
408 if (!--tries) {
409 LOG_DBG("shub: Timeout waiting for operation to complete");
410 return -ETIMEDOUT;
411 }
412 k_msleep(1);
413 lsm6dso_sh_status_mainpage_get(ctx, &status);
414 } while (status.sens_hub_endop == 0);
415
416 return 1;
417 }
418
lsm6dso_shub_enable(const struct device * dev,uint8_t enable)419 static void lsm6dso_shub_enable(const struct device *dev, uint8_t enable)
420 {
421 const struct lsm6dso_config *cfg = dev->config;
422 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
423 struct lsm6dso_data *data = dev->data;
424
425 /* Enable Accel @26hz */
426 if (!data->accel_freq) {
427 uint8_t odr = (enable) ? 2 : 0;
428
429 if (lsm6dso_xl_data_rate_set(ctx, odr) < 0) {
430 LOG_DBG("shub: failed to set XL sampling rate");
431 return;
432 }
433 }
434
435 if (enable) {
436 lsm6dso_status_master_t status;
437
438 /* Clear any pending status flags */
439 lsm6dso_sh_status_mainpage_get(ctx, &status);
440 }
441
442 if (lsm6dso_sh_master_set(ctx, enable) < 0) {
443 LOG_DBG("shub: failed to set master on");
444 lsm6dso_mem_bank_set(ctx, LSM6DSO_USER_BANK);
445 return;
446 }
447
448 if (!enable) {
449 /* wait 300us (necessary per AN5192 §7.2.1) */
450 k_busy_wait(300);
451 }
452 }
453
454 /* must be called with master on */
lsm6dso_shub_check_slv0_nack(stmdev_ctx_t * ctx)455 static int lsm6dso_shub_check_slv0_nack(stmdev_ctx_t *ctx)
456 {
457 lsm6dso_status_master_t status;
458
459 if (lsm6dso_sh_status_get(ctx, &status) < 0) {
460 LOG_DBG("shub: error reading embedded reg");
461 return -EIO;
462 }
463
464 if (status.slave0_nack) {
465 LOG_DBG("shub: TRGT 0 nacked");
466 return -EIO;
467 }
468
469 return 0;
470 }
471
472 /*
473 * use TRGT 0 for generic read to target device
474 */
lsm6dso_shub_read_target_reg(const struct device * dev,uint8_t trgt_addr,uint8_t trgt_reg,uint8_t * value,uint16_t len)475 static int lsm6dso_shub_read_target_reg(const struct device *dev,
476 uint8_t trgt_addr, uint8_t trgt_reg,
477 uint8_t *value, uint16_t len)
478 {
479 const struct lsm6dso_config *cfg = dev->config;
480 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
481 lsm6dso_sh_cfg_read_t trgt_cfg;
482
483 trgt_cfg.slv_add = trgt_addr;
484 trgt_cfg.slv_subadd = trgt_reg;
485 trgt_cfg.slv_len = len;
486
487 lsm6dso_sh_slv_cfg_read(ctx, 0, &trgt_cfg);
488
489 /* turn SH on, wait for shub i2c read to finish */
490 lsm6dso_shub_enable(dev, 1);
491 lsm6dso_shub_wait_completed(ctx);
492
493 /* read data from external target */
494 if (lsm6dso_sh_read_data_raw_get(ctx, value, len) < 0) {
495 LOG_DBG("shub: error reading sensor data");
496 return -EIO;
497 }
498
499 if (lsm6dso_shub_check_slv0_nack(ctx) < 0) {
500 lsm6dso_shub_enable(dev, 0);
501 return -EIO;
502 }
503
504 lsm6dso_shub_enable(dev, 0);
505 return 0;
506 }
507
508 /*
509 * use TRGT 0 to configure target device
510 */
lsm6dso_shub_write_target_reg(const struct device * dev,uint8_t trgt_addr,uint8_t trgt_reg,uint8_t * value,uint16_t len)511 static int lsm6dso_shub_write_target_reg(const struct device *dev,
512 uint8_t trgt_addr, uint8_t trgt_reg,
513 uint8_t *value, uint16_t len)
514 {
515 const struct lsm6dso_config *cfg = dev->config;
516 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
517 lsm6dso_sh_cfg_write_t trgt_cfg;
518 uint8_t cnt = 0U;
519
520 lsm6dso_shub_enable(dev, 0);
521
522 while (cnt < len) {
523 trgt_cfg.slv0_add = trgt_addr;
524 trgt_cfg.slv0_subadd = trgt_reg + cnt;
525 trgt_cfg.slv0_data = value[cnt];
526
527 lsm6dso_sh_cfg_write(ctx, &trgt_cfg);
528
529 /* turn SH on, wait for shub i2c write to finish */
530 lsm6dso_shub_enable(dev, 1);
531 lsm6dso_shub_wait_completed(ctx);
532
533 if (lsm6dso_shub_check_slv0_nack(ctx) < 0) {
534 lsm6dso_shub_enable(dev, 0);
535 return -EIO;
536 }
537
538 lsm6dso_shub_enable(dev, 0);
539
540 cnt++;
541 }
542
543 /* Put TRGT 0 in IDLE mode */
544 trgt_cfg.slv0_add = 0x7;
545 trgt_cfg.slv0_subadd = 0x0;
546 trgt_cfg.slv0_data = 0x0;
547 lsm6dso_sh_cfg_write(ctx, &trgt_cfg);
548
549 return 0;
550 }
551
552 /*
553 * TARGETs configurations:
554 *
555 * - TARGET 0: used for configuring all target devices
556 * - TARGET 1: used as data read channel for external target device #1
557 * - TARGET 2: used as data read channel for external target device #2
558 * - TARGET 3: used for generic reads while data channel is enabled
559 */
lsm6dso_shub_set_data_channel(const struct device * dev)560 static int lsm6dso_shub_set_data_channel(const struct device *dev)
561 {
562 struct lsm6dso_data *data = dev->data;
563 const struct lsm6dso_config *cfg = dev->config;
564 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
565 uint8_t n;
566 struct lsm6dso_shub_slist *sp;
567 lsm6dso_sh_cfg_read_t trgt_cfg;
568
569 /* Configure shub data channels to access external targets */
570 for (n = 0; n < data->num_ext_dev; n++) {
571 sp = &lsm6dso_shub_slist[data->shub_ext[n]];
572
573 trgt_cfg.slv_add = sp->ext_i2c_addr;
574 trgt_cfg.slv_subadd = sp->out_data_addr;
575 trgt_cfg.slv_len = sp->out_data_len;
576
577 if (lsm6dso_sh_slv_cfg_read(ctx, n + 1, &trgt_cfg) < 0) {
578 LOG_DBG("shub: error configuring shub for ext targets");
579 return -EIO;
580 }
581 }
582
583 /* Configure the master */
584 lsm6dso_aux_sens_on_t aux = LSM6DSO_SLV_0_1_2;
585
586 if (lsm6dso_sh_slave_connected_set(ctx, aux) < 0) {
587 LOG_DBG("shub: error setting aux sensors");
588 return -EIO;
589 }
590
591
592 /* turn SH on, no need to wait for 1st shub i2c read, if any, to complete */
593 lsm6dso_shub_enable(dev, 1);
594
595 return 0;
596 }
597
lsm6dso_shub_get_idx(const struct device * dev,enum sensor_channel type)598 int lsm6dso_shub_get_idx(const struct device *dev, enum sensor_channel type)
599 {
600 uint8_t n;
601 struct lsm6dso_data *data = dev->data;
602 struct lsm6dso_shub_slist *sp;
603
604 for (n = 0; n < data->num_ext_dev; n++) {
605 sp = &lsm6dso_shub_slist[data->shub_ext[n]];
606
607 if (sp->type == type) {
608 return n;
609 }
610 }
611
612 LOG_ERR("shub: dev %s type %d not supported", dev->name, type);
613 return -ENOTSUP;
614 }
615
lsm6dso_shub_fetch_external_devs(const struct device * dev)616 int lsm6dso_shub_fetch_external_devs(const struct device *dev)
617 {
618 uint8_t n;
619 const struct lsm6dso_config *cfg = dev->config;
620 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
621 struct lsm6dso_data *data = dev->data;
622 struct lsm6dso_shub_slist *sp;
623
624 /* read data from external target */
625 if (lsm6dso_mem_bank_set(ctx, LSM6DSO_SENSOR_HUB_BANK) < 0) {
626 LOG_DBG("failed to enter SENSOR_HUB bank");
627 return -EIO;
628 }
629
630 for (n = 0; n < data->num_ext_dev; n++) {
631 sp = &lsm6dso_shub_slist[data->shub_ext[n]];
632
633 if (lsm6dso_read_reg(ctx, sp->sh_out_reg,
634 data->ext_data[n], sp->out_data_len) < 0) {
635 LOG_DBG("shub: failed to read sample");
636 (void) lsm6dso_mem_bank_set(ctx, LSM6DSO_USER_BANK);
637 return -EIO;
638 }
639 }
640
641 return lsm6dso_mem_bank_set(ctx, LSM6DSO_USER_BANK);
642 }
643
lsm6dso_shub_config(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)644 int lsm6dso_shub_config(const struct device *dev, enum sensor_channel chan,
645 enum sensor_attribute attr,
646 const struct sensor_value *val)
647 {
648 struct lsm6dso_data *data = dev->data;
649 struct lsm6dso_shub_slist *sp = NULL;
650 uint8_t n;
651
652 for (n = 0; n < data->num_ext_dev; n++) {
653 sp = &lsm6dso_shub_slist[data->shub_ext[n]];
654
655 if (sp->type == chan) {
656 break;
657 }
658 }
659
660 if (n == data->num_ext_dev) {
661 LOG_DBG("shub: %s chan %d not supported", dev->name, chan);
662 return -ENOTSUP;
663 }
664
665 if (sp == NULL || sp->dev_conf == NULL) {
666 LOG_DBG("shub: chan not configurable");
667 return -ENOTSUP;
668 }
669
670 return sp->dev_conf(dev, sp->ext_i2c_addr, chan, attr, val);
671 }
672
lsm6dso_shub_init(const struct device * dev)673 int lsm6dso_shub_init(const struct device *dev)
674 {
675 struct lsm6dso_data *data = dev->data;
676 const struct lsm6dso_config *cfg = dev->config;
677 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
678 uint8_t i, n = 0, regn;
679 uint8_t chip_id;
680 struct lsm6dso_shub_slist *sp;
681
682 LOG_INF("shub: start sensorhub for %s", dev->name);
683
684 /* This must be set or lsm6dso_shub_write_target_reg() will repeatedly write the same reg */
685 if (lsm6dso_sh_write_mode_set(ctx, LSM6DSO_ONLY_FIRST_CYCLE) < 0) {
686 LOG_DBG("shub: error setting write once");
687 return -EIO;
688 }
689
690 for (n = 0; n < ARRAY_SIZE(lsm6dso_shub_slist); n++) {
691 if (data->num_ext_dev >= LSM6DSO_SHUB_MAX_NUM_TARGETS) {
692 break;
693 }
694
695 chip_id = 0;
696 sp = &lsm6dso_shub_slist[n];
697
698 /*
699 * The external sensor may have different I2C address.
700 * So, try them one by one until we read the correct
701 * chip ID.
702 */
703 for (i = 0U; i < ARRAY_SIZE(sp->i2c_addr); i++) {
704 if (lsm6dso_shub_read_target_reg(dev,
705 sp->i2c_addr[i],
706 sp->wai_addr,
707 &chip_id, 1) < 0) {
708 LOG_DBG("shub: failed reading chip id");
709 continue;
710 }
711 if (chip_id == sp->wai_val) {
712 break;
713 }
714 }
715
716 if (i >= ARRAY_SIZE(sp->i2c_addr)) {
717 LOG_DBG("shub: invalid chip id 0x%x", chip_id);
718 continue;
719 }
720 LOG_INF("shub: Ext Device Chip Id: %02x", chip_id);
721 sp->ext_i2c_addr = sp->i2c_addr[i];
722
723 data->shub_ext[data->num_ext_dev++] = n;
724 }
725
726 LOG_DBG("shub: dev %s - num_ext_dev %d", dev->name, data->num_ext_dev);
727 if (data->num_ext_dev == 0) {
728 LOG_ERR("shub: no target devices found");
729 return -EINVAL;
730 }
731
732 /* init external devices */
733 for (n = 0, regn = 0; n < data->num_ext_dev; n++) {
734 sp = &lsm6dso_shub_slist[data->shub_ext[n]];
735 sp->sh_out_reg = LSM6DSO_SENSOR_HUB_1 + regn;
736 regn += sp->out_data_len;
737 sp->dev_init(dev, sp->ext_i2c_addr);
738 }
739
740 lsm6dso_shub_set_data_channel(dev);
741
742 return 0;
743 }
744