1 /* ST Microelectronics IIS2ICLX 2-axis accelerometer sensor driver
2 *
3 * Copyright (c) 2020 STMicroelectronics
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Datasheet:
8 * https://www.st.com/resource/en/datasheet/iis2iclx.pdf
9 */
10
11 #define DT_DRV_COMPAT st_iis2iclx
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 "iis2iclx.h"
22
23 LOG_MODULE_DECLARE(IIS2ICLX, CONFIG_SENSOR_LOG_LEVEL);
24
25 #define IIS2ICLX_SHUB_DATA_OUT 0x02
26
27 #define IIS2ICLX_SHUB_SLV0_ADDR 0x15
28 #define IIS2ICLX_SHUB_SLV0_SUBADDR 0x16
29 #define IIS2ICLX_SHUB_SLV0_CONFIG 0x17
30 #define IIS2ICLX_SHUB_SLV1_ADDR 0x18
31 #define IIS2ICLX_SHUB_SLV1_SUBADDR 0x19
32 #define IIS2ICLX_SHUB_SLV1_CONFIG 0x1A
33 #define IIS2ICLX_SHUB_SLV2_ADDR 0x1B
34 #define IIS2ICLX_SHUB_SLV2_SUBADDR 0x1C
35 #define IIS2ICLX_SHUB_SLV2_CONFIG 0x1D
36 #define IIS2ICLX_SHUB_SLV3_ADDR 0x1E
37 #define IIS2ICLX_SHUB_SLV3_SUBADDR 0x1F
38 #define IIS2ICLX_SHUB_SLV3_CONFIG 0x20
39 #define IIS2ICLX_SHUB_SLV0_DATAWRITE 0x21
40
41 #define IIS2ICLX_SHUB_STATUS_MASTER 0x22
42 #define IIS2ICLX_SHUB_STATUS_SLV0_NACK BIT(3)
43 #define IIS2ICLX_SHUB_STATUS_ENDOP BIT(0)
44
45 #define IIS2ICLX_SHUB_SLVX_WRITE 0x0
46 #define IIS2ICLX_SHUB_SLVX_READ 0x1
47
48 static int iis2iclx_shub_write_slave_reg(const struct device *dev,
49 uint8_t slv_addr, uint8_t slv_reg,
50 uint8_t *value, uint16_t len);
51 static int iis2iclx_shub_read_slave_reg(const struct device *dev,
52 uint8_t slv_addr, uint8_t slv_reg,
53 uint8_t *value, uint16_t len);
54 static void iis2iclx_shub_enable(const struct device *dev, uint8_t enable);
55
56 /*
57 * LIS2MDL magn device specific part
58 */
59 #if defined(CONFIG_IIS2ICLX_EXT_LIS2MDL) || defined(CONFIG_IIS2ICLX_EXT_IIS2MDC)
60
61 #define LIS2MDL_CFG_REG_A 0x60
62 #define LIS2MDL_CFG_REG_B 0x61
63 #define LIS2MDL_CFG_REG_C 0x62
64 #define LIS2MDL_STATUS_REG 0x67
65
66 #define LIS2MDL_SW_RESET 0x20
67 #define LIS2MDL_ODR_10HZ 0x00
68 #define LIS2MDL_ODR_100HZ 0x0C
69 #define LIS2MDL_OFF_CANC 0x02
70 #define LIS2MDL_SENSITIVITY 1500
71
iis2iclx_lis2mdl_init(const struct device * dev,uint8_t i2c_addr)72 static int iis2iclx_lis2mdl_init(const struct device *dev, uint8_t i2c_addr)
73 {
74 struct iis2iclx_data *data = dev->data;
75 uint8_t mag_cfg[2];
76
77 data->magn_gain = LIS2MDL_SENSITIVITY;
78
79 /* sw reset device */
80 mag_cfg[0] = LIS2MDL_SW_RESET;
81 iis2iclx_shub_write_slave_reg(dev, i2c_addr,
82 LIS2MDL_CFG_REG_A, mag_cfg, 1);
83
84 k_sleep(K_MSEC(10)); /* turn-on time in ms */
85
86 /* configure mag */
87 mag_cfg[0] = LIS2MDL_ODR_10HZ;
88 mag_cfg[1] = LIS2MDL_OFF_CANC;
89 iis2iclx_shub_write_slave_reg(dev, i2c_addr,
90 LIS2MDL_CFG_REG_A, mag_cfg, 2);
91
92 return 0;
93 }
94
95 static const uint16_t lis2mdl_map[] = {10, 20, 50, 100};
96
iis2iclx_lis2mdl_odr_set(const struct device * dev,uint8_t i2c_addr,uint16_t freq)97 static int iis2iclx_lis2mdl_odr_set(const struct device *dev,
98 uint8_t i2c_addr, uint16_t freq)
99 {
100 uint8_t odr, cfg;
101
102 for (odr = 0; odr < ARRAY_SIZE(lis2mdl_map); odr++) {
103 if (freq == lis2mdl_map[odr]) {
104 break;
105 }
106 }
107
108 if (odr == ARRAY_SIZE(lis2mdl_map)) {
109 LOG_ERR("shub: LIS2MDL freq val %d not supported.", freq);
110 return -ENOTSUP;
111 }
112
113 cfg = (odr << 2);
114 iis2iclx_shub_write_slave_reg(dev, i2c_addr,
115 LIS2MDL_CFG_REG_A, &cfg, 1);
116
117 iis2iclx_shub_enable(dev, 1);
118 return 0;
119 }
120
iis2iclx_lis2mdl_conf(const struct device * dev,uint8_t i2c_addr,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)121 static int iis2iclx_lis2mdl_conf(const struct device *dev, uint8_t i2c_addr,
122 enum sensor_channel chan,
123 enum sensor_attribute attr,
124 const struct sensor_value *val)
125 {
126 switch (attr) {
127 case SENSOR_ATTR_SAMPLING_FREQUENCY:
128 return iis2iclx_lis2mdl_odr_set(dev, i2c_addr, val->val1);
129 default:
130 LOG_ERR("shub: LIS2MDL attribute not supported.");
131 return -ENOTSUP;
132 }
133
134 return 0;
135 }
136 #endif /* CONFIG_IIS2ICLX_EXT_LIS2MDL || CONFIG_IIS2ICLX_EXT_IIS2MDC */
137
138 /*
139 * HTS221 humidity device specific part
140 */
141 #ifdef CONFIG_IIS2ICLX_EXT_HTS221
142
143 #define HTS221_AUTOINCREMENT BIT(7)
144
145 #define HTS221_REG_CTRL1 0x20
146 #define HTS221_ODR_1HZ 0x01
147 #define HTS221_BDU 0x04
148 #define HTS221_PD 0x80
149
150 #define HTS221_REG_CONV_START 0x30
151
hts221_read_conv_data(const struct device * dev,uint8_t i2c_addr)152 static int hts221_read_conv_data(const struct device *dev,
153 uint8_t i2c_addr)
154 {
155 struct iis2iclx_data *data = dev->data;
156 uint8_t buf[16], i;
157 struct hts221_data *ht = &data->hts221;
158
159 for (i = 0; i < sizeof(buf); i += 7) {
160 unsigned char len = MIN(7, sizeof(buf) - i);
161
162 if (iis2iclx_shub_read_slave_reg(dev, i2c_addr,
163 (HTS221_REG_CONV_START + i) |
164 HTS221_AUTOINCREMENT,
165 &buf[i], len) < 0) {
166 LOG_ERR("shub: failed to read hts221 conv data");
167 return -EIO;
168 }
169 }
170
171 ht->y0 = buf[0] / 2;
172 ht->y1 = buf[1] / 2;
173 ht->x0 = buf[6] | (buf[7] << 8);
174 ht->x1 = buf[10] | (buf[11] << 8);
175
176 return 0;
177 }
178
iis2iclx_hts221_init(const struct device * dev,uint8_t i2c_addr)179 static int iis2iclx_hts221_init(const struct device *dev, uint8_t i2c_addr)
180 {
181 uint8_t hum_cfg;
182
183 /* configure ODR and BDU */
184 hum_cfg = HTS221_ODR_1HZ | HTS221_BDU | HTS221_PD;
185 iis2iclx_shub_write_slave_reg(dev, i2c_addr,
186 HTS221_REG_CTRL1, &hum_cfg, 1);
187
188 return hts221_read_conv_data(dev, i2c_addr);
189 }
190
191 static const uint16_t hts221_map[] = {0, 1, 7, 12};
192
iis2iclx_hts221_odr_set(const struct device * dev,uint8_t i2c_addr,uint16_t freq)193 static int iis2iclx_hts221_odr_set(const struct device *dev,
194 uint8_t i2c_addr, uint16_t freq)
195 {
196 uint8_t odr, cfg;
197
198 for (odr = 0; odr < ARRAY_SIZE(hts221_map); odr++) {
199 if (freq == hts221_map[odr]) {
200 break;
201 }
202 }
203
204 if (odr == ARRAY_SIZE(hts221_map)) {
205 LOG_ERR("shub: HTS221 freq val %d not supported.", freq);
206 return -ENOTSUP;
207 }
208
209 cfg = odr | HTS221_BDU | HTS221_PD;
210 iis2iclx_shub_write_slave_reg(dev, i2c_addr,
211 HTS221_REG_CTRL1, &cfg, 1);
212
213 iis2iclx_shub_enable(dev, 1);
214 return 0;
215 }
216
iis2iclx_hts221_conf(const struct device * dev,uint8_t i2c_addr,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)217 static int iis2iclx_hts221_conf(const struct device *dev, uint8_t i2c_addr,
218 enum sensor_channel chan,
219 enum sensor_attribute attr,
220 const struct sensor_value *val)
221 {
222 switch (attr) {
223 case SENSOR_ATTR_SAMPLING_FREQUENCY:
224 return iis2iclx_hts221_odr_set(dev, i2c_addr, val->val1);
225 default:
226 LOG_ERR("shub: HTS221 attribute not supported.");
227 return -ENOTSUP;
228 }
229
230 return 0;
231 }
232 #endif /* CONFIG_IIS2ICLX_EXT_HTS221 */
233
234 /*
235 * LPS22HB baro/temp device specific part
236 */
237 #ifdef CONFIG_IIS2ICLX_EXT_LPS22HB
238
239 #define LPS22HB_CTRL_REG1 0x10
240 #define LPS22HB_CTRL_REG2 0x11
241
242 #define LPS22HB_SW_RESET 0x04
243 #define LPS22HB_ODR_10HZ 0x20
244 #define LPS22HB_LPF_EN 0x08
245 #define LPS22HB_BDU_EN 0x02
246
iis2iclx_lps22hb_init(const struct device * dev,uint8_t i2c_addr)247 static int iis2iclx_lps22hb_init(const struct device *dev, uint8_t i2c_addr)
248 {
249 uint8_t baro_cfg[2];
250
251 /* sw reset device */
252 baro_cfg[0] = LPS22HB_SW_RESET;
253 iis2iclx_shub_write_slave_reg(dev, i2c_addr,
254 LPS22HB_CTRL_REG2, baro_cfg, 1);
255
256 k_sleep(K_MSEC(1)); /* turn-on time in ms */
257
258 /* configure device */
259 baro_cfg[0] = LPS22HB_ODR_10HZ | LPS22HB_LPF_EN | LPS22HB_BDU_EN;
260 iis2iclx_shub_write_slave_reg(dev, i2c_addr,
261 LPS22HB_CTRL_REG1, baro_cfg, 1);
262
263 return 0;
264 }
265 #endif /* CONFIG_IIS2ICLX_EXT_LPS22HB */
266
267 /*
268 * LPS22HH baro/temp device specific part
269 */
270 #ifdef CONFIG_IIS2ICLX_EXT_LPS22HH
271
272 #define LPS22HH_CTRL_REG1 0x10
273 #define LPS22HH_CTRL_REG2 0x11
274
275 #define LPS22HH_SW_RESET 0x04
276 #define LPS22HH_IF_ADD_INC 0x10
277 #define LPS22HH_ODR_10HZ 0x20
278 #define LPS22HH_LPF_EN 0x08
279 #define LPS22HH_BDU_EN 0x02
280
iis2iclx_lps22hh_init(const struct device * dev,uint8_t i2c_addr)281 static int iis2iclx_lps22hh_init(const struct device *dev, uint8_t i2c_addr)
282 {
283 uint8_t baro_cfg[2];
284
285 /* sw reset device */
286 baro_cfg[0] = LPS22HH_SW_RESET;
287 iis2iclx_shub_write_slave_reg(dev, i2c_addr,
288 LPS22HH_CTRL_REG2, baro_cfg, 1);
289
290 k_sleep(K_MSEC(100)); /* turn-on time in ms */
291
292 /* configure device */
293 baro_cfg[0] = LPS22HH_IF_ADD_INC;
294 iis2iclx_shub_write_slave_reg(dev, i2c_addr,
295 LPS22HH_CTRL_REG2, baro_cfg, 1);
296
297 baro_cfg[0] = LPS22HH_ODR_10HZ | LPS22HH_LPF_EN | LPS22HH_BDU_EN;
298 iis2iclx_shub_write_slave_reg(dev, i2c_addr,
299 LPS22HH_CTRL_REG1, baro_cfg, 1);
300
301 return 0;
302 }
303
304 static const uint16_t lps22hh_map[] = {0, 1, 10, 25, 50, 75, 100, 200};
305
iis2iclx_lps22hh_odr_set(const struct device * dev,uint8_t i2c_addr,uint16_t freq)306 static int iis2iclx_lps22hh_odr_set(const struct device *dev,
307 uint8_t i2c_addr, uint16_t freq)
308 {
309 uint8_t odr, cfg;
310
311 for (odr = 0; odr < ARRAY_SIZE(lps22hh_map); odr++) {
312 if (freq == lps22hh_map[odr]) {
313 break;
314 }
315 }
316
317 if (odr == ARRAY_SIZE(lps22hh_map)) {
318 LOG_ERR("shub: LPS22HH freq val %d not supported.", freq);
319 return -ENOTSUP;
320 }
321
322 cfg = (odr << 4) | LPS22HH_LPF_EN | LPS22HH_BDU_EN;
323 iis2iclx_shub_write_slave_reg(dev, i2c_addr,
324 LPS22HH_CTRL_REG1, &cfg, 1);
325
326 iis2iclx_shub_enable(dev, 1);
327 return 0;
328 }
329
iis2iclx_lps22hh_conf(const struct device * dev,uint8_t i2c_addr,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)330 static int iis2iclx_lps22hh_conf(const struct device *dev, uint8_t i2c_addr,
331 enum sensor_channel chan,
332 enum sensor_attribute attr,
333 const struct sensor_value *val)
334 {
335 switch (attr) {
336 case SENSOR_ATTR_SAMPLING_FREQUENCY:
337 return iis2iclx_lps22hh_odr_set(data, i2c_addr, val->val1);
338 default:
339 LOG_ERR("shub: LPS22HH attribute not supported.");
340 return -ENOTSUP;
341 }
342
343 return 0;
344 }
345 #endif /* CONFIG_IIS2ICLX_EXT_LPS22HH */
346
347 /* List of supported external sensors */
348 static struct iis2iclx_shub_slist {
349 enum sensor_channel type;
350 uint8_t i2c_addr[2];
351 uint8_t ext_i2c_addr;
352 uint8_t wai_addr;
353 uint8_t wai_val;
354 uint8_t out_data_addr;
355 uint8_t out_data_len;
356 uint8_t sh_out_reg;
357 int (*dev_init)(const struct device *dev, uint8_t i2c_addr);
358 int (*dev_conf)(const struct device *dev, uint8_t i2c_addr,
359 enum sensor_channel chan, enum sensor_attribute attr,
360 const struct sensor_value *val);
361 } iis2iclx_shub_slist[] = {
362 #if defined(CONFIG_IIS2ICLX_EXT_LIS2MDL) || defined(CONFIG_IIS2ICLX_EXT_IIS2MDC)
363 {
364 /* LIS2MDL */
365 .type = SENSOR_CHAN_MAGN_XYZ,
366 .i2c_addr = { 0x1E },
367 .wai_addr = 0x4F,
368 .wai_val = 0x40,
369 .out_data_addr = 0x68,
370 .out_data_len = 0x06,
371 .dev_init = (iis2iclx_lis2mdl_init),
372 .dev_conf = (iis2iclx_lis2mdl_conf),
373 },
374 #endif /* CONFIG_IIS2ICLX_EXT_LIS2MDL || CONFIG_IIS2ICLX_EXT_IIS2MDC */
375
376 #ifdef CONFIG_IIS2ICLX_EXT_HTS221
377 {
378 /* HTS221 */
379 .type = SENSOR_CHAN_HUMIDITY,
380 .i2c_addr = { 0x5F },
381 .wai_addr = 0x0F,
382 .wai_val = 0xBC,
383 .out_data_addr = 0x28 | HTS221_AUTOINCREMENT,
384 .out_data_len = 0x02,
385 .dev_init = (iis2iclx_hts221_init),
386 .dev_conf = (iis2iclx_hts221_conf),
387 },
388 #endif /* CONFIG_IIS2ICLX_EXT_HTS221 */
389
390 #ifdef CONFIG_IIS2ICLX_EXT_LPS22HB
391 {
392 /* LPS22HB */
393 .type = SENSOR_CHAN_PRESS,
394 .i2c_addr = { 0x5C, 0x5D },
395 .wai_addr = 0x0F,
396 .wai_val = 0xB1,
397 .out_data_addr = 0x28,
398 .out_data_len = 0x05,
399 .dev_init = (iis2iclx_lps22hb_init),
400 },
401 #endif /* CONFIG_IIS2ICLX_EXT_LPS22HB */
402
403 #ifdef CONFIG_IIS2ICLX_EXT_LPS22HH
404 {
405 /* LPS22HH */
406 .type = SENSOR_CHAN_PRESS,
407 .i2c_addr = { 0x5C, 0x5D },
408 .wai_addr = 0x0F,
409 .wai_val = 0xB3,
410 .out_data_addr = 0x28,
411 .out_data_len = 0x05,
412 .dev_init = (iis2iclx_lps22hh_init),
413 .dev_conf = (iis2iclx_lps22hh_conf),
414 },
415 #endif /* CONFIG_IIS2ICLX_EXT_LPS22HH */
416 };
417
iis2iclx_shub_wait_completed(const struct iis2iclx_config * cfg)418 static inline void iis2iclx_shub_wait_completed(const struct iis2iclx_config *cfg)
419 {
420 iis2iclx_status_master_t status;
421
422 do {
423 k_msleep(1);
424 iis2iclx_sh_status_get((stmdev_ctx_t *)&cfg->ctx, &status);
425 } while (status.sens_hub_endop == 0);
426 }
427
iis2iclx_shub_embedded_en(const struct iis2iclx_config * cfg,bool on)428 static inline void iis2iclx_shub_embedded_en(const struct iis2iclx_config *cfg,
429 bool on)
430 {
431 if (on) {
432 (void) iis2iclx_mem_bank_set((stmdev_ctx_t *)&cfg->ctx,
433 IIS2ICLX_SENSOR_HUB_BANK);
434 } else {
435 (void) iis2iclx_mem_bank_set((stmdev_ctx_t *)&cfg->ctx,
436 IIS2ICLX_USER_BANK);
437 }
438
439 k_busy_wait(150);
440 }
441
iis2iclx_shub_read_embedded_regs(const struct iis2iclx_config * cfg,uint8_t reg_addr,uint8_t * value,int len)442 static int iis2iclx_shub_read_embedded_regs(const struct iis2iclx_config *cfg,
443 uint8_t reg_addr,
444 uint8_t *value, int len)
445 {
446 iis2iclx_shub_embedded_en(cfg, true);
447
448 if (iis2iclx_read_reg((stmdev_ctx_t *)&cfg->ctx, reg_addr, value, len) < 0) {
449 LOG_ERR("shub: failed to read external reg: %02x", reg_addr);
450 iis2iclx_shub_embedded_en(cfg, false);
451 return -EIO;
452 }
453
454 iis2iclx_shub_embedded_en(cfg, false);
455
456 return 0;
457 }
458
iis2iclx_shub_write_embedded_regs(const struct iis2iclx_config * cfg,uint8_t reg_addr,uint8_t * value,uint8_t len)459 static int iis2iclx_shub_write_embedded_regs(const struct iis2iclx_config *cfg,
460 uint8_t reg_addr,
461 uint8_t *value, uint8_t len)
462 {
463 iis2iclx_shub_embedded_en(cfg, true);
464
465 if (iis2iclx_write_reg((stmdev_ctx_t *)&cfg->ctx, reg_addr, value, len) < 0) {
466 LOG_ERR("shub: failed to write external reg: %02x", reg_addr);
467 iis2iclx_shub_embedded_en(cfg, false);
468 return -EIO;
469 }
470
471 iis2iclx_shub_embedded_en(cfg, false);
472
473 return 0;
474 }
475
iis2iclx_shub_enable(const struct device * dev,uint8_t enable)476 static void iis2iclx_shub_enable(const struct device *dev, uint8_t enable)
477 {
478 const struct iis2iclx_config *cfg = dev->config;
479 struct iis2iclx_data *data = dev->data;
480
481 /* Enable Accel @26hz */
482 if (!data->accel_freq) {
483 uint8_t odr = (enable) ? 2 : 0;
484
485 if (iis2iclx_xl_data_rate_set((stmdev_ctx_t *)&cfg->ctx, odr) < 0) {
486 LOG_DBG("shub: failed to set XL sampling rate");
487 return;
488 }
489 }
490
491 iis2iclx_shub_embedded_en(cfg, true);
492
493 if (iis2iclx_sh_master_set((stmdev_ctx_t *)&cfg->ctx, enable) < 0) {
494 LOG_DBG("shub: failed to set master on");
495 iis2iclx_shub_embedded_en(cfg, false);
496 return;
497 }
498
499 iis2iclx_shub_embedded_en(cfg, false);
500 }
501
502 /* must be called with master on */
iis2iclx_shub_check_slv0_nack(const struct iis2iclx_config * cfg)503 static int iis2iclx_shub_check_slv0_nack(const struct iis2iclx_config *cfg)
504 {
505 uint8_t status;
506
507 if (iis2iclx_shub_read_embedded_regs(cfg, IIS2ICLX_SHUB_STATUS_MASTER,
508 &status, 1) < 0) {
509 LOG_ERR("shub: error reading embedded reg");
510 return -EIO;
511 }
512
513 if (status & (IIS2ICLX_SHUB_STATUS_SLV0_NACK)) {
514 LOG_ERR("shub: SLV0 nacked");
515 return -EIO;
516 }
517
518 return 0;
519 }
520
521 /*
522 * use SLV0 for generic read to slave device
523 */
iis2iclx_shub_read_slave_reg(const struct device * dev,uint8_t slv_addr,uint8_t slv_reg,uint8_t * value,uint16_t len)524 static int iis2iclx_shub_read_slave_reg(const struct device *dev,
525 uint8_t slv_addr, uint8_t slv_reg,
526 uint8_t *value, uint16_t len)
527 {
528 const struct iis2iclx_config *cfg = dev->config;
529 uint8_t slave[3];
530
531 slave[0] = (slv_addr << 1) | IIS2ICLX_SHUB_SLVX_READ;
532 slave[1] = slv_reg;
533 slave[2] = (len & 0x7);
534
535 if (iis2iclx_shub_write_embedded_regs(cfg, IIS2ICLX_SHUB_SLV0_ADDR,
536 slave, 3) < 0) {
537 LOG_ERR("shub: error writing embedded reg");
538 return -EIO;
539 }
540
541 /* turn SH on */
542 iis2iclx_shub_enable(dev, 1);
543 iis2iclx_shub_wait_completed(cfg);
544
545 if (iis2iclx_shub_check_slv0_nack(cfg) < 0) {
546 iis2iclx_shub_enable(dev, 0);
547 return -EIO;
548 }
549
550 /* read data from external slave */
551 iis2iclx_shub_embedded_en(cfg, true);
552 if (iis2iclx_read_reg((stmdev_ctx_t *)&cfg->ctx, IIS2ICLX_SHUB_DATA_OUT,
553 value, len) < 0) {
554 LOG_ERR("shub: error reading sensor data");
555 iis2iclx_shub_embedded_en(cfg, false);
556 return -EIO;
557 }
558 iis2iclx_shub_embedded_en(cfg, false);
559
560 iis2iclx_shub_enable(dev, 0);
561 return 0;
562 }
563
564 /*
565 * use SLV0 to configure slave device
566 */
iis2iclx_shub_write_slave_reg(const struct device * dev,uint8_t slv_addr,uint8_t slv_reg,uint8_t * value,uint16_t len)567 static int iis2iclx_shub_write_slave_reg(const struct device *dev,
568 uint8_t slv_addr, uint8_t slv_reg,
569 uint8_t *value, uint16_t len)
570 {
571 const struct iis2iclx_config *cfg = dev->config;
572 uint8_t slv_cfg[3];
573 uint8_t cnt = 0U;
574
575 while (cnt < len) {
576 slv_cfg[0] = (slv_addr << 1) & ~IIS2ICLX_SHUB_SLVX_READ;
577 slv_cfg[1] = slv_reg + cnt;
578
579 if (iis2iclx_shub_write_embedded_regs(cfg,
580 IIS2ICLX_SHUB_SLV0_ADDR,
581 slv_cfg, 2) < 0) {
582 LOG_ERR("shub: error writing embedded reg");
583 return -EIO;
584 }
585
586 slv_cfg[0] = value[cnt];
587 if (iis2iclx_shub_write_embedded_regs(cfg,
588 IIS2ICLX_SHUB_SLV0_DATAWRITE,
589 slv_cfg, 1) < 0) {
590 LOG_ERR("shub: error writing embedded reg");
591 return -EIO;
592 }
593
594 /* turn SH on */
595 iis2iclx_shub_enable(dev, 1);
596 iis2iclx_shub_wait_completed(cfg);
597
598 if (iis2iclx_shub_check_slv0_nack(cfg) < 0) {
599 iis2iclx_shub_enable(dev, 0);
600 return -EIO;
601 }
602
603 iis2iclx_shub_enable(dev, 0);
604
605 cnt++;
606 }
607
608 /* Put SLV0 in IDLE mode */
609 slv_cfg[0] = 0x7;
610 slv_cfg[1] = 0x0;
611 slv_cfg[2] = 0x0;
612 if (iis2iclx_shub_write_embedded_regs(cfg, IIS2ICLX_SHUB_SLV0_ADDR,
613 slv_cfg, 3) < 0) {
614 LOG_ERR("shub: error writing embedded reg");
615 return -EIO;
616 }
617
618 return 0;
619 }
620
621 /*
622 * SLAVEs configurations:
623 *
624 * - SLAVE 0: used for configuring all slave devices
625 * - SLAVE 1: used as data read channel for external slave device #1
626 * - SLAVE 2: used as data read channel for external slave device #2
627 * - SLAVE 3: used for generic reads while data channel is enabled
628 */
iis2iclx_shub_set_data_channel(const struct device * dev)629 static int iis2iclx_shub_set_data_channel(const struct device *dev)
630 {
631 struct iis2iclx_data *data = dev->data;
632 const struct iis2iclx_config *cfg = dev->config;
633 uint8_t n, i, slv_cfg[6];
634 struct iis2iclx_shub_slist *sp;
635
636 /* Set data channel for slave devices */
637 for (n = 0; n < data->num_ext_dev; n++) {
638 sp = &iis2iclx_shub_slist[data->shub_ext[n]];
639
640 i = n * 3;
641 slv_cfg[i] = (sp->ext_i2c_addr << 1) | IIS2ICLX_SHUB_SLVX_READ;
642 slv_cfg[i + 1] = sp->out_data_addr;
643 slv_cfg[i + 2] = sp->out_data_len;
644 }
645
646 if (iis2iclx_shub_write_embedded_regs(cfg,
647 IIS2ICLX_SHUB_SLV1_ADDR,
648 slv_cfg, n*3) < 0) {
649 LOG_ERR("shub: error writing embedded reg");
650 return -EIO;
651 }
652
653 /* Configure the master */
654 iis2iclx_aux_sens_on_t aux = IIS2ICLX_SLV_0_1_2;
655
656 if (iis2iclx_sh_slave_connected_set((stmdev_ctx_t *)&cfg->ctx, aux) < 0) {
657 LOG_ERR("shub: error setting aux sensors");
658 return -EIO;
659 }
660
661 iis2iclx_write_once_t wo = IIS2ICLX_ONLY_FIRST_CYCLE;
662
663 if (iis2iclx_sh_write_mode_set((stmdev_ctx_t *)&cfg->ctx, wo) < 0) {
664 LOG_ERR("shub: error setting write once");
665 return -EIO;
666 }
667
668
669 /* turn SH on */
670 iis2iclx_shub_enable(dev, 1);
671 iis2iclx_shub_wait_completed(cfg);
672
673 return 0;
674 }
675
iis2iclx_shub_get_idx(const struct device * dev,enum sensor_channel type)676 int iis2iclx_shub_get_idx(const struct device *dev, enum sensor_channel type)
677 {
678 uint8_t n;
679 struct iis2iclx_shub_slist *sp;
680 struct iis2iclx_data *data = dev->data;
681
682 for (n = 0; n < data->num_ext_dev; n++) {
683 sp = &iis2iclx_shub_slist[data->shub_ext[n]];
684
685 if (sp->type == type) {
686 return n;
687 }
688 }
689
690 return -ENOTSUP;
691 }
692
iis2iclx_shub_fetch_external_devs(const struct device * dev)693 int iis2iclx_shub_fetch_external_devs(const struct device *dev)
694 {
695 uint8_t n;
696 const struct iis2iclx_config *cfg = dev->config;
697 struct iis2iclx_data *data = dev->data;
698 struct iis2iclx_shub_slist *sp;
699
700 /* read data from external slave */
701 iis2iclx_shub_embedded_en(cfg, true);
702
703 for (n = 0; n < data->num_ext_dev; n++) {
704 sp = &iis2iclx_shub_slist[data->shub_ext[n]];
705
706 if (iis2iclx_read_reg((stmdev_ctx_t *)&cfg->ctx, sp->sh_out_reg,
707 data->ext_data[n], sp->out_data_len) < 0) {
708 LOG_ERR("shub: failed to read sample");
709 iis2iclx_shub_embedded_en(cfg, false);
710 return -EIO;
711 }
712 }
713
714 iis2iclx_shub_embedded_en(cfg, false);
715
716 return 0;
717 }
718
iis2iclx_shub_config(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)719 int iis2iclx_shub_config(const struct device *dev, enum sensor_channel chan,
720 enum sensor_attribute attr,
721 const struct sensor_value *val)
722 {
723 struct iis2iclx_data *data = dev->data;
724 struct iis2iclx_shub_slist *sp = NULL;
725 uint8_t n;
726
727 for (n = 0; n < data->num_ext_dev; n++) {
728 sp = &iis2iclx_shub_slist[data->shub_ext[n]];
729
730 if (sp->type == chan) {
731 break;
732 }
733 }
734
735 if (n == data->num_ext_dev) {
736 LOG_ERR("shub: chan not supported");
737 return -ENOTSUP;
738 }
739
740 if (sp == NULL || sp->dev_conf == NULL) {
741 LOG_ERR("shub: chan not configurable");
742 return -ENOTSUP;
743 }
744
745 return sp->dev_conf(dev, sp->ext_i2c_addr, chan, attr, val);
746 }
747
iis2iclx_shub_init(const struct device * dev)748 int iis2iclx_shub_init(const struct device *dev)
749 {
750 uint8_t i, n = 0, regn;
751 uint8_t chip_id;
752 struct iis2iclx_shub_slist *sp;
753 struct iis2iclx_data *data = dev->data;
754
755 LOG_INF("shub: start sensorhub for %s", dev->name);
756 for (n = 0; n < ARRAY_SIZE(iis2iclx_shub_slist); n++) {
757 if (data->num_ext_dev >= IIS2ICLX_SHUB_MAX_NUM_SLVS) {
758 break;
759 }
760
761 chip_id = 0;
762 sp = &iis2iclx_shub_slist[n];
763
764 /*
765 * The external sensor may have different I2C address.
766 * So, try them one by one until we read the correct
767 * chip ID.
768 */
769 for (i = 0U; i < ARRAY_SIZE(sp->i2c_addr); i++) {
770 if (iis2iclx_shub_read_slave_reg(dev,
771 sp->i2c_addr[i],
772 sp->wai_addr,
773 &chip_id, 1) < 0) {
774 continue;
775 }
776 if (chip_id == sp->wai_val) {
777 break;
778 }
779 }
780
781 if (i >= ARRAY_SIZE(sp->i2c_addr)) {
782 LOG_DBG("shub: invalid chip id 0x%x", chip_id);
783 continue;
784 }
785 LOG_INF("shub: Ext Device Chip Id: 0x%02x", chip_id);
786 sp->ext_i2c_addr = sp->i2c_addr[i];
787
788 data->shub_ext[data->num_ext_dev++] = n;
789 }
790
791 LOG_DBG("shub: dev %s - num_ext_dev %d", dev->name, data->num_ext_dev);
792 if (data->num_ext_dev == 0) {
793 LOG_WRN("shub: no slave devices found");
794 return -ENOTSUP;
795 }
796
797 /* init external devices */
798 for (n = 0, regn = 0; n < data->num_ext_dev; n++) {
799 sp = &iis2iclx_shub_slist[data->shub_ext[n]];
800 sp->sh_out_reg = IIS2ICLX_SHUB_DATA_OUT + regn;
801 regn += sp->out_data_len;
802 sp->dev_init(dev, sp->ext_i2c_addr);
803 }
804
805 iis2iclx_shub_set_data_channel(dev);
806
807 return 0;
808 }
809