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