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