lsm6dso_shub.c 19 KB

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