Icm20948AuxCompassAkm.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. /*
  2. * ________________________________________________________________________________________________________
  3. * Copyright © 2014-2015 InvenSense Inc. Portions Copyright © 2014-2015 Movea. All rights reserved.
  4. * This software, related documentation and any modifications thereto (collectively “Software”) is subject
  5. * to InvenSense and its licensors' intellectual property rights under U.S. and international copyright and
  6. * other intellectual property rights laws.
  7. * InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
  8. * and any use, reproduction, disclosure or distribution of the Software without an express license
  9. * agreement from InvenSense is strictly prohibited.
  10. * ________________________________________________________________________________________________________
  11. */
  12. #include "Icm20948.h"
  13. #include "Icm20948AuxCompassAkm.h"
  14. #include "Icm20948Defs.h"
  15. #include "Icm20948DataConverter.h"
  16. #include "Icm20948AuxTransport.h"
  17. #include "Icm20948Dmp3Driver.h"
  18. /* AKM definitions */
  19. #define REG_AKM_ID 0x00
  20. #define REG_AKM_INFO 0x01
  21. #define REG_AKM_STATUS 0x02
  22. #define REG_AKM_MEASURE_DATA 0x03
  23. #define REG_AKM_MODE 0x0A
  24. #define REG_AKM_ST_CTRL 0x0C
  25. #define REG_AKM_SENSITIVITY 0x10
  26. #define REG_AKM8963_CNTL1 0x0A
  27. #if (MEMS_CHIP == HW_ICM20648)
  28. /* AK09911 register definition */
  29. #define REG_AK09911_DMP_READ 0x3
  30. #define REG_AK09911_STATUS1 0x10
  31. #define REG_AK09911_CNTL2 0x31
  32. #define REG_AK09911_SENSITIVITY 0x60
  33. #define REG_AK09911_MEASURE_DATA 0x11
  34. /* AK09912 register definition */
  35. #define REG_AK09912_DMP_READ 0x3
  36. #define REG_AK09912_STATUS1 0x10
  37. #define REG_AK09912_CNTL1 0x30
  38. #define REG_AK09912_CNTL2 0x31
  39. #define REG_AK09912_SENSITIVITY 0x60
  40. #define REG_AK09912_MEASURE_DATA 0x11
  41. #endif
  42. /* AK09916 register definition */
  43. #define REG_AK09916_DMP_READ 0x3
  44. #define REG_AK09916_STATUS1 0x10
  45. #define REG_AK09916_STATUS2 0x18
  46. #define REG_AK09916_CNTL2 0x31
  47. #define REG_AK09916_CNTL3 0x32
  48. #define REG_AK09916_MEASURE_DATA 0x11
  49. #define REG_AK09916_TEST 0x33
  50. //-- REG WIA
  51. #define DATA_AKM_ID 0x48
  52. //-- REG CNTL2
  53. #define DATA_AKM_MODE_PD 0x00
  54. #define DATA_AKM_MODE_SM 0x01
  55. #define DATA_AKM_MODE_ST 0x08
  56. #define DATA_AK09911_MODE_ST 0x10
  57. #define DATA_AK09912_MODE_ST 0x10
  58. #define DATA_AK09916_MODE_ST 0x10
  59. #define DATA_AKM_MODE_FR 0x0F
  60. #define DATA_AK09911_MODE_FR 0x1F
  61. #define DATA_AK09912_MODE_FR 0x1F
  62. // AK09916 doesn't support Fuse ROM access
  63. #define DATA_AKM_SELF_TEST 0x40
  64. //-- REG Status 1
  65. #define DATA_AKM_DRDY 0x01
  66. #define DATA_AKM9916_DOR 0x01
  67. #define DATA_AKM8963_BIT 0x10
  68. #if (MEMS_CHIP == HW_ICM20648)
  69. /* 0.3 uT * (1 << 30) */
  70. #define DATA_AKM8975_SCALE 322122547
  71. /* 0.6 uT * (1 << 30) */
  72. #define DATA_AKM8972_SCALE 644245094
  73. /* 0.6 uT * (1 << 30) */
  74. #define DATA_AKM8963_SCALE0 644245094
  75. /* 0.6 uT * (1 << 30) */
  76. #define DATA_AK09911_SCALE 644245094
  77. /* 0.15 uT * (1 << 30) */
  78. #define DATA_AK09912_SCALE 161061273
  79. #endif
  80. /* 0.15 uT * (1 << 30) */
  81. #define DATA_AKM8963_SCALE1 161061273
  82. /* 0.15 uT * (1 << 30) */
  83. #define DATA_AK09916_SCALE 161061273
  84. #define DATA_AKM8963_SCALE_SHIFT 4
  85. #define DATA_AKM_MIN_READ_TIME (9 * NSEC_PER_MSEC)
  86. /* AK09912C NSF */
  87. /* 0:disable, 1:Low, 2:Middle, 3:High */
  88. #define DATA_AK9912_NSF 1
  89. #define DATA_AK9912_NSF_SHIFT 5
  90. #define DEF_ST_COMPASS_WAIT_MIN (10 * 1000)
  91. #define DEF_ST_COMPASS_WAIT_MAX (15 * 1000)
  92. #define DEF_ST_COMPASS_TRY_TIMES 10
  93. #define DEF_ST_COMPASS_8963_SHIFT 2
  94. #define DEF_ST_COMPASS_9916_SHIFT 2
  95. #define X 0
  96. #define Y 1
  97. #define Z 2
  98. /* milliseconds between each access */
  99. #define AKM_RATE_SCALE 10
  100. #define DATA_AKM_99_BYTES_DMP 10
  101. #define DATA_AKM_89_BYTES_DMP 9
  102. #if (MEMS_CHIP == HW_ICM20648)
  103. static const short AKM8975_ST_Lower[3] = {-100, -100, -1000};
  104. static const short AKM8975_ST_Upper[3] = {100, 100, -300};
  105. static const short AKM8972_ST_Lower[3] = {-50, -50, -500};
  106. static const short AKM8972_ST_Upper[3] = {50, 50, -100};
  107. static const short AKM8963_ST_Lower[3] = {-200, -200, -3200};
  108. static const short AKM8963_ST_Upper[3] = {200, 200, -800};
  109. static const short AK09911_ST_Lower[3] = {-30, -30, -400};
  110. static const short AK09911_ST_Upper[3] = {30, 30, -50};
  111. static const short AK09912_ST_Lower[3] = {-200, -200, -1600};
  112. static const short AK09912_ST_Upper[3] = {200, 200, -400};
  113. #endif
  114. static const short AK09916_ST_Lower[3] = {-200, -200, -1000};
  115. static const short AK09916_ST_Upper[3] = {200, 200, -200};
  116. void inv_icm20948_register_aux_compass(struct inv_icm20948 * s,
  117. enum inv_icm20948_compass_id compass_id, uint8_t compass_i2c_addr)
  118. {
  119. switch(compass_id) {
  120. case INV_ICM20948_COMPASS_ID_AK09911:
  121. s->secondary_state.compass_slave_id = HW_AK09911;
  122. s->secondary_state.compass_chip_addr = compass_i2c_addr;
  123. s->secondary_state.compass_state = INV_ICM20948_COMPASS_INITED;
  124. /* initialise mounting matrix of compass to identity akm9911 */
  125. s->mounting_matrix_secondary_compass[0] = -1 ;
  126. s->mounting_matrix_secondary_compass[4] = -1;
  127. s->mounting_matrix_secondary_compass[8] = 1;
  128. break;
  129. case INV_ICM20948_COMPASS_ID_AK09912:
  130. s->secondary_state.compass_slave_id = HW_AK09912;
  131. s->secondary_state.compass_chip_addr = compass_i2c_addr;
  132. s->secondary_state.compass_state = INV_ICM20948_COMPASS_INITED;
  133. /* initialise mounting matrix of compass to identity akm9912 */
  134. s->mounting_matrix_secondary_compass[0] = 1 ;
  135. s->mounting_matrix_secondary_compass[4] = 1;
  136. s->mounting_matrix_secondary_compass[8] = 1;
  137. break;
  138. case INV_ICM20948_COMPASS_ID_AK08963:
  139. s->secondary_state.compass_slave_id = HW_AK8963;
  140. s->secondary_state.compass_chip_addr = compass_i2c_addr;
  141. s->secondary_state.compass_state = INV_ICM20948_COMPASS_INITED;
  142. /* initialise mounting matrix of compass to identity akm8963 */
  143. s->mounting_matrix_secondary_compass[0] = 1;
  144. s->mounting_matrix_secondary_compass[4] = 1;
  145. s->mounting_matrix_secondary_compass[8] = 1;
  146. break;
  147. case INV_ICM20948_COMPASS_ID_AK09916:
  148. s->secondary_state.compass_slave_id = HW_AK09916;
  149. s->secondary_state.compass_chip_addr = compass_i2c_addr;
  150. s->secondary_state.compass_state = INV_ICM20948_COMPASS_INITED;
  151. /* initialise mounting matrix of compass to identity akm9916 */
  152. s->mounting_matrix_secondary_compass[0] = 1 ;
  153. s->mounting_matrix_secondary_compass[4] = -1;
  154. s->mounting_matrix_secondary_compass[8] = -1;
  155. break;
  156. default:
  157. s->secondary_state.compass_slave_id = 0;
  158. s->secondary_state.compass_chip_addr = 0;
  159. s->secondary_state.compass_state = INV_ICM20948_COMPASS_RESET;
  160. }
  161. }
  162. /*
  163. * inv_icm20948_setup_compass_akm() - Configure akm series compass.
  164. */
  165. int inv_icm20948_setup_compass_akm(struct inv_icm20948 * s)
  166. {
  167. int result;
  168. unsigned char data[4];
  169. #if (MEMS_CHIP != HW_ICM20948)
  170. uint8_t sens, cmd;
  171. #endif
  172. //reset variable to initial values
  173. memset(s->secondary_state.final_matrix, 0, sizeof(s->secondary_state.final_matrix));
  174. memset(s->secondary_state.compass_sens, 0, sizeof(s->secondary_state.compass_sens));
  175. s->secondary_state.scale = 0;
  176. s->secondary_state.dmp_on = 1;
  177. s->secondary_state.secondary_resume_compass_state = 0;
  178. /* Read WHOAMI through I2C SLV for compass */
  179. result = inv_icm20948_execute_read_secondary(s, COMPASS_I2C_SLV_READ, s->secondary_state.compass_chip_addr, REG_AKM_ID, 1, data);
  180. if (result) {
  181. // inv_log("Read secondary error: Compass.\r\n");
  182. return result;
  183. }
  184. if (data[0] != DATA_AKM_ID) {
  185. // inv_log("Compass not found!!\r\n");
  186. return -1;
  187. }
  188. // inv_log("Compass found.\r\n");
  189. /* setup upper and lower limit of self-test */
  190. #if (MEMS_CHIP == HW_ICM20948)
  191. s->secondary_state.st_upper = AK09916_ST_Upper;
  192. s->secondary_state.st_lower = AK09916_ST_Lower;
  193. #else
  194. if (HW_AK8975 == s->secondary_state.compass_slave_id) {
  195. s->secondary_state.st_upper = AKM8975_ST_Upper;
  196. s->secondary_state.st_lower = AKM8975_ST_Lower;
  197. } else if (HW_AK8972 == s->secondary_state.compass_slave_id) {
  198. s->secondary_state.st_upper = AKM8972_ST_Upper;
  199. s->secondary_state.st_lower = AKM8972_ST_Lower;
  200. } else if (HW_AK8963 == s->secondary_state.compass_slave_id) {
  201. s->secondary_state.st_upper = AKM8963_ST_Upper;
  202. s->secondary_state.st_lower = AKM8963_ST_Lower;
  203. } else if (HW_AK09911 == s->secondary_state.compass_slave_id) {
  204. s->secondary_state.st_upper = AK09911_ST_Upper;
  205. s->secondary_state.st_lower = AK09911_ST_Lower;
  206. } else if (HW_AK09912 == s->secondary_state.compass_slave_id) {
  207. s->secondary_state.st_upper = AK09912_ST_Upper;
  208. s->secondary_state.st_lower = AK09912_ST_Lower;
  209. } else if (HW_AK09916 == s->secondary_state.compass_slave_id) {
  210. s->secondary_state.st_upper = AK09916_ST_Upper;
  211. s->secondary_state.st_lower = AK09916_ST_Lower;
  212. } else {
  213. return -1;
  214. }
  215. #endif
  216. #if (MEMS_CHIP == HW_ICM20948)
  217. /* Read conf and configure compass through I2C SLV for compass and subsequent channel */
  218. s->secondary_state.mode_reg_addr = REG_AK09916_CNTL2;
  219. // no sensitivity adjustment value
  220. s->secondary_state.compass_sens[0] = 128;
  221. s->secondary_state.compass_sens[1] = 128;
  222. s->secondary_state.compass_sens[2] = 128;
  223. #else
  224. /* Read conf and configure compass through I2C SLV for compass and subsequent channel */
  225. if (HW_AK09916 == s->secondary_state.compass_slave_id) {
  226. s->secondary_state.mode_reg_addr = REG_AK09916_CNTL2;
  227. // no sensitivity adjustment value
  228. s->secondary_state.compass_sens[0] = 128;
  229. s->secondary_state.compass_sens[1] = 128;
  230. s->secondary_state.compass_sens[2] = 128;
  231. }
  232. else {
  233. // Fuse ROM access not possible for ak9916
  234. /* set AKM to Fuse ROM access mode */
  235. if (HW_AK09911 == s->secondary_state.compass_slave_id) {
  236. s->secondary_state.mode_reg_addr = REG_AK09911_CNTL2;
  237. sens = REG_AK09911_SENSITIVITY;
  238. cmd = DATA_AK09911_MODE_FR;
  239. } else if (HW_AK09912 == s->secondary_state.compass_slave_id) {
  240. s->secondary_state.mode_reg_addr = REG_AK09912_CNTL2;
  241. sens = REG_AK09912_SENSITIVITY;
  242. cmd = DATA_AK09912_MODE_FR;
  243. } else {
  244. s->secondary_state.mode_reg_addr = REG_AKM_MODE;
  245. sens = REG_AKM_SENSITIVITY;
  246. cmd = DATA_AKM_MODE_FR;
  247. }
  248. result = inv_icm20948_read_secondary(s, COMPASS_I2C_SLV_READ, s->secondary_state.compass_chip_addr, sens, THREE_AXES);
  249. if (result)
  250. return result;
  251. // activate FUSE_ROM mode to CNTL2
  252. result = inv_icm20948_execute_write_secondary(s, COMPASS_I2C_SLV_WRITE, s->secondary_state.compass_chip_addr,
  253. s->secondary_state.mode_reg_addr, cmd);
  254. if (result)
  255. return result;
  256. // read sensitivity
  257. result = inv_icm20948_read_mems_reg(s, REG_EXT_SLV_SENS_DATA_00, THREE_AXES, s->secondary_state.compass_sens);
  258. if (result)
  259. return result;
  260. }
  261. //aply noise suppression filter (only available for 9912)
  262. if (HW_AK09912 == s->secondary_state.compass_slave_id) {
  263. result = inv_icm20948_execute_write_secondary(s, COMPASS_I2C_SLV_WRITE, s->secondary_state.compass_chip_addr, REG_AK09912_CNTL1,
  264. DATA_AK9912_NSF << DATA_AK9912_NSF_SHIFT);
  265. if (result)
  266. return result;
  267. }
  268. #endif
  269. /* Set compass in power down through I2C SLV for compass */
  270. result = inv_icm20948_execute_write_secondary(s, COMPASS_I2C_SLV_WRITE, s->secondary_state.compass_chip_addr, s->secondary_state.mode_reg_addr, DATA_AKM_MODE_PD);
  271. if (result)
  272. return result;
  273. s->secondary_state.secondary_resume_compass_state = 1;
  274. s->secondary_state.compass_state = INV_ICM20948_COMPASS_SETUP;
  275. return inv_icm20948_suspend_akm(s);
  276. }
  277. int inv_icm20948_check_akm_self_test(struct inv_icm20948 * s)
  278. {
  279. int result;
  280. unsigned char data[6], mode, addr;
  281. unsigned char counter;
  282. short x, y, z;
  283. unsigned char *sens;
  284. int shift;
  285. unsigned char slv_ctrl[2];
  286. unsigned char odr_cfg;
  287. #if (MEMS_CHIP != HW_ICM20948)
  288. unsigned char cntl;
  289. #endif
  290. addr = s->secondary_state.compass_chip_addr;
  291. sens = s->secondary_state.compass_sens;
  292. /* back up registers */
  293. /* SLV0_CTRL */
  294. result = inv_icm20948_read_mems_reg(s, REG_I2C_SLV0_CTRL, 1, &slv_ctrl[0]);
  295. if (result)
  296. return result;
  297. result = inv_icm20948_write_single_mems_reg(s, REG_I2C_SLV0_CTRL, 0);
  298. if (result)
  299. return result;
  300. /* SLV1_CTRL */
  301. result = inv_icm20948_read_mems_reg(s, REG_I2C_SLV1_CTRL, 1, &slv_ctrl[1]);
  302. if (result)
  303. return result;
  304. result = inv_icm20948_write_single_mems_reg(s, REG_I2C_SLV1_CTRL, 0);
  305. if (result)
  306. return result;
  307. /* I2C_MST ODR */
  308. result = inv_icm20948_read_mems_reg(s, REG_I2C_MST_ODR_CONFIG, 1, &odr_cfg);
  309. if (result)
  310. return result;
  311. result = inv_icm20948_write_single_mems_reg(s, REG_I2C_MST_ODR_CONFIG, 0);
  312. if (result)
  313. return result;
  314. #if (MEMS_CHIP == HW_ICM20948)
  315. mode = REG_AK09916_CNTL2;
  316. #else
  317. if (HW_AK09911 == s->secondary_state.compass_slave_id)
  318. mode = REG_AK09911_CNTL2;
  319. else if (HW_AK09912 == s->secondary_state.compass_slave_id)
  320. mode = REG_AK09912_CNTL2;
  321. else if (HW_AK09916 == s->secondary_state.compass_slave_id)
  322. mode = REG_AK09916_CNTL2;
  323. else
  324. mode = REG_AKM_MODE;
  325. #endif
  326. /* set to power down mode */
  327. result = inv_icm20948_execute_write_secondary(s, 0, addr, mode, DATA_AKM_MODE_PD);
  328. if (result)
  329. goto AKM_fail;
  330. /* write 1 to ASTC register */
  331. if ((HW_AK09911 != s->secondary_state.compass_slave_id) &&
  332. (HW_AK09912 != s->secondary_state.compass_slave_id)) {
  333. result = inv_icm20948_execute_write_secondary(s, 0, addr, REG_AKM_ST_CTRL, DATA_AKM_SELF_TEST);
  334. if (result)
  335. goto AKM_fail;
  336. }
  337. #if (MEMS_CHIP == HW_ICM20948)
  338. result = inv_icm20948_execute_write_secondary(s, 0, addr, mode, DATA_AK09916_MODE_ST);
  339. #else
  340. /* set self test mode */
  341. if (HW_AK09911 == s->secondary_state.compass_slave_id)
  342. result = inv_icm20948_execute_write_secondary(s, 0, addr, mode, DATA_AK09911_MODE_ST);
  343. else if (HW_AK09912 == s->secondary_state.compass_slave_id)
  344. result = inv_icm20948_execute_write_secondary(s, 0, addr, mode, DATA_AK09912_MODE_ST);
  345. else if (HW_AK09916 == s->secondary_state.compass_slave_id)
  346. result = inv_icm20948_execute_write_secondary(s, 0, addr, mode, DATA_AK09916_MODE_ST);
  347. else
  348. result = inv_icm20948_execute_write_secondary(s, 0, addr, mode, DATA_AKM_MODE_ST);
  349. #endif
  350. if (result)
  351. goto AKM_fail;
  352. counter = DEF_ST_COMPASS_TRY_TIMES;
  353. while (counter > 0) {
  354. // usleep_range(DEF_ST_COMPASS_WAIT_MIN, DEF_ST_COMPASS_WAIT_MAX);
  355. inv_icm20948_sleep(15);
  356. #if (MEMS_CHIP == HW_ICM20948)
  357. result = inv_icm20948_execute_read_secondary(s, 0, addr, REG_AK09916_STATUS1, 1, data);
  358. #else
  359. if (HW_AK09911 == s->secondary_state.compass_slave_id)
  360. result = inv_icm20948_execute_read_secondary(s, 0, addr, REG_AK09911_STATUS1, 1, data);
  361. else if (HW_AK09912 == s->secondary_state.compass_slave_id)
  362. result = inv_icm20948_execute_read_secondary(s, 0, addr, REG_AK09912_STATUS1, 1, data);
  363. else if (HW_AK09916 == s->secondary_state.compass_slave_id)
  364. result = inv_icm20948_execute_read_secondary(s, 0, addr, REG_AK09916_STATUS1, 1, data);
  365. else
  366. result = inv_icm20948_execute_read_secondary(s, 0, addr, REG_AKM_STATUS, 1, data);
  367. #endif
  368. if (result)
  369. goto AKM_fail;
  370. if ((data[0] & DATA_AKM_DRDY) == 0)
  371. counter--;
  372. else
  373. counter = 0;
  374. }
  375. if ((data[0] & DATA_AKM_DRDY) == 0) {
  376. result = -1;
  377. goto AKM_fail;
  378. }
  379. #if (MEMS_CHIP == HW_ICM20948)
  380. result = inv_icm20948_execute_read_secondary(s, 0, addr, REG_AK09916_MEASURE_DATA, BYTES_PER_SENSOR, data);
  381. #else
  382. if (HW_AK09911 == s->secondary_state.compass_slave_id) {
  383. result = inv_icm20948_execute_read_secondary(s, 0, addr, REG_AK09911_MEASURE_DATA, BYTES_PER_SENSOR, data);
  384. } else if (HW_AK09912 == s->secondary_state.compass_slave_id) {
  385. result = inv_icm20948_execute_read_secondary(s, 0, addr, REG_AK09912_MEASURE_DATA, BYTES_PER_SENSOR, data);
  386. } else if (HW_AK09916 == s->secondary_state.compass_slave_id) {
  387. result = inv_icm20948_execute_read_secondary(s, 0, addr, REG_AK09916_MEASURE_DATA, BYTES_PER_SENSOR, data);
  388. } else {
  389. result = inv_icm20948_execute_read_secondary(s, 0, addr, REG_AKM_MEASURE_DATA, BYTES_PER_SENSOR, data);
  390. }
  391. #endif
  392. if (result)
  393. goto AKM_fail;
  394. x = ((short)data[1])<<8|data[0];
  395. y = ((short)data[3])<<8|data[2];
  396. z = ((short)data[5])<<8|data[4];
  397. if (HW_AK09911 == s->secondary_state.compass_slave_id)
  398. shift = 7;
  399. else
  400. shift = 8;
  401. x = ((x * (sens[0] + 128)) >> shift);
  402. y = ((y * (sens[1] + 128)) >> shift);
  403. z = ((z * (sens[2] + 128)) >> shift);
  404. #if (MEMS_CHIP == HW_ICM20648)
  405. if (HW_AK8963 == s->secondary_state.compass_slave_id) {
  406. result = inv_icm20948_execute_read_secondary(s, 0, addr, REG_AKM8963_CNTL1, 1, &cntl);
  407. if (result)
  408. goto AKM_fail;
  409. if (0 == (cntl & DATA_AKM8963_BIT)) {
  410. x <<= DEF_ST_COMPASS_8963_SHIFT;
  411. y <<= DEF_ST_COMPASS_8963_SHIFT;
  412. z <<= DEF_ST_COMPASS_8963_SHIFT;
  413. }
  414. }
  415. #endif
  416. result = -1;
  417. if (x > s->secondary_state.st_upper[0] || x < s->secondary_state.st_lower[0])
  418. goto AKM_fail;
  419. if (y > s->secondary_state.st_upper[1] || y < s->secondary_state.st_lower[1])
  420. goto AKM_fail;
  421. if (z > s->secondary_state.st_upper[2] || z < s->secondary_state.st_lower[2])
  422. goto AKM_fail;
  423. result = 0;
  424. AKM_fail:
  425. /*write 0 to ASTC register */
  426. if ((HW_AK09911 != s->secondary_state.compass_slave_id) &&
  427. (HW_AK09912 != s->secondary_state.compass_slave_id) &&
  428. (HW_AK09916 != s->secondary_state.compass_slave_id)) {
  429. result |= inv_icm20948_execute_write_secondary(s, 0, addr, REG_AKM_ST_CTRL, 0);
  430. }
  431. /*set to power down mode */
  432. result |= inv_icm20948_execute_write_secondary(s, 0, addr, mode, DATA_AKM_MODE_PD);
  433. return result;
  434. }
  435. /*
  436. * inv_icm20948_write_akm_scale() - Configure the akm scale range.
  437. */
  438. int inv_icm20948_write_akm_scale(struct inv_icm20948 * s, int data)
  439. {
  440. char d, en;
  441. int result;
  442. if (HW_AK8963 != s->secondary_state.compass_slave_id)
  443. return 0;
  444. en = !!data;
  445. if (s->secondary_state.scale == en)
  446. return 0;
  447. d = (DATA_AKM_MODE_SM | (en << DATA_AKM8963_SCALE_SHIFT));
  448. result = inv_icm20948_write_single_mems_reg(s, REG_I2C_SLV1_DO, d);
  449. if (result)
  450. return result;
  451. s->secondary_state.scale = en;
  452. return 0;
  453. }
  454. /*
  455. * inv_icm20948_read_akm_scale() - show AKM scale.
  456. */
  457. int inv_icm20948_read_akm_scale(struct inv_icm20948 * s, int *scale)
  458. {
  459. #if (MEMS_CHIP == HW_ICM20948)
  460. (void)s;
  461. *scale = DATA_AK09916_SCALE;
  462. #else
  463. if (HW_AK8975 == s->secondary_state.compass_slave_id)
  464. *scale = DATA_AKM8975_SCALE;
  465. else if (HW_AK8972 == s->secondary_state.compass_slave_id)
  466. *scale = DATA_AKM8972_SCALE;
  467. else if (HW_AK8963 == s->secondary_state.compass_slave_id)
  468. if (s->secondary_state.scale)
  469. *scale = DATA_AKM8963_SCALE1;
  470. else
  471. *scale = DATA_AKM8963_SCALE0;
  472. else if (HW_AK09911 == s->secondary_state.compass_slave_id)
  473. *scale = DATA_AK09911_SCALE;
  474. else if (HW_AK09912 == s->secondary_state.compass_slave_id)
  475. *scale = DATA_AK09912_SCALE;
  476. else if (HW_AK09916 == s->secondary_state.compass_slave_id)
  477. *scale = DATA_AK09916_SCALE;
  478. else
  479. return -1;
  480. #endif
  481. return 0;
  482. }
  483. int inv_icm20948_suspend_akm(struct inv_icm20948 * s)
  484. {
  485. int result;
  486. if (!s->secondary_state.secondary_resume_compass_state)
  487. return 0;
  488. /* slave 0 is disabled */
  489. result = inv_icm20948_secondary_stop_channel(s, COMPASS_I2C_SLV_READ);
  490. /* slave 1 is disabled */
  491. result |= inv_icm20948_secondary_stop_channel(s, COMPASS_I2C_SLV_WRITE);
  492. if (result)
  493. return result;
  494. // Switch off I2C Interface as compass is alone
  495. result |= inv_icm20948_secondary_disable_i2c(s);
  496. s->secondary_state.secondary_resume_compass_state = 0;
  497. return result;
  498. }
  499. int inv_icm20948_resume_akm(struct inv_icm20948 * s)
  500. {
  501. int result;
  502. uint8_t reg_addr, bytes;
  503. unsigned char lDataToWrite;
  504. if (s->secondary_state.secondary_resume_compass_state)
  505. return 0;
  506. /* slave 0 is used to read data from compass */
  507. /*read mode */
  508. #if (MEMS_CHIP == HW_ICM20948)
  509. if (s->secondary_state.dmp_on) {
  510. reg_addr = REG_AK09916_DMP_READ;
  511. bytes = DATA_AKM_99_BYTES_DMP;
  512. } else {
  513. reg_addr = REG_AK09916_STATUS1;
  514. bytes = DATA_AKM_99_BYTES_DMP - 1;
  515. }
  516. #else
  517. /* AKM status register address is 1 */
  518. if (HW_AK09911 == s->secondary_state.compass_slave_id) {
  519. if (s->secondary_state.dmp_on) {
  520. reg_addr = REG_AK09911_DMP_READ;
  521. bytes = DATA_AKM_99_BYTES_DMP;
  522. } else {
  523. reg_addr = REG_AK09911_STATUS1;
  524. bytes = DATA_AKM_99_BYTES_DMP - 1;
  525. }
  526. } else if (HW_AK09912 == s->secondary_state.compass_slave_id) {
  527. if (s->secondary_state.dmp_on) {
  528. reg_addr = REG_AK09912_DMP_READ;
  529. bytes = DATA_AKM_99_BYTES_DMP;
  530. } else {
  531. reg_addr = REG_AK09912_STATUS1;
  532. bytes = DATA_AKM_99_BYTES_DMP - 1;
  533. }
  534. } else if (HW_AK09916 == s->secondary_state.compass_slave_id) {
  535. if (s->secondary_state.dmp_on) {
  536. reg_addr = REG_AK09916_DMP_READ;
  537. bytes = DATA_AKM_99_BYTES_DMP;
  538. } else {
  539. reg_addr = REG_AK09916_STATUS1;
  540. bytes = DATA_AKM_99_BYTES_DMP - 1;
  541. }
  542. } else {
  543. if (s->secondary_state.dmp_on) {
  544. reg_addr = REG_AKM_INFO;
  545. bytes = DATA_AKM_89_BYTES_DMP;
  546. } else {
  547. reg_addr = REG_AKM_STATUS;
  548. bytes = DATA_AKM_89_BYTES_DMP - 1;
  549. }
  550. }
  551. #endif
  552. /* slave 0 is enabled, read 10 or 8 bytes from here depending on compass type, swap bytes to feed DMP */
  553. result = inv_icm20948_read_secondary(s, COMPASS_I2C_SLV_READ, s->secondary_state.compass_chip_addr, reg_addr, INV_MPU_BIT_GRP | INV_MPU_BIT_BYTE_SW | bytes);
  554. if (result)
  555. return result;
  556. #if (MEMS_CHIP == HW_ICM20948)
  557. lDataToWrite = DATA_AKM_MODE_SM;
  558. #else
  559. /* slave 1 is used to write one-shot accquisition configuration to compass */
  560. /* output data for slave 1 is fixed, single measure mode */
  561. s->secondary_state.scale = 1;
  562. if (HW_AK8975 == s->secondary_state.compass_slave_id) {
  563. lDataToWrite = DATA_AKM_MODE_SM;
  564. } else if (HW_AK8972 == s->secondary_state.compass_slave_id) {
  565. lDataToWrite = DATA_AKM_MODE_SM;
  566. } else if (HW_AK8963 == s->secondary_state.compass_slave_id) {
  567. lDataToWrite = DATA_AKM_MODE_SM |
  568. (s->secondary_state.scale << DATA_AKM8963_SCALE_SHIFT);
  569. } else if (HW_AK09911 == s->secondary_state.compass_slave_id) {
  570. lDataToWrite = DATA_AKM_MODE_SM;
  571. } else if (HW_AK09912 == s->secondary_state.compass_slave_id) {
  572. lDataToWrite = DATA_AKM_MODE_SM;
  573. } else if (HW_AK09916 == s->secondary_state.compass_slave_id) {
  574. lDataToWrite = DATA_AKM_MODE_SM;
  575. } else {
  576. return -1;
  577. }
  578. #endif
  579. result = inv_icm20948_write_secondary(s, COMPASS_I2C_SLV_WRITE, s->secondary_state.compass_chip_addr, s->secondary_state.mode_reg_addr, lDataToWrite);
  580. if (result)
  581. return result;
  582. result |= inv_icm20948_secondary_enable_i2c(s);
  583. s->secondary_state.secondary_resume_compass_state = 1;
  584. return result;
  585. }
  586. char inv_icm20948_compass_getstate(struct inv_icm20948 * s)
  587. {
  588. return s->secondary_state.secondary_resume_compass_state;
  589. }
  590. int inv_icm20948_compass_isconnected(struct inv_icm20948 * s)
  591. {
  592. if(s->secondary_state.compass_state == INV_ICM20948_COMPASS_SETUP) {
  593. return 1;
  594. } else {
  595. return 0;
  596. }
  597. }
  598. /**
  599. * @brief Set up the soft-iron matrix for compass in DMP.
  600. * @param[in] Accel/Gyro mounting matrix
  601. * @param[in] Compass mounting matrix
  602. * @return 0 if successful.
  603. */
  604. int inv_icm20948_compass_dmp_cal(struct inv_icm20948 * s, const signed char *m, const signed char *compass_m)
  605. {
  606. int8_t trans[NINE_ELEM];
  607. int tmp_m[NINE_ELEM];
  608. int i, j, k;
  609. int sens[THREE_AXES];
  610. int scale;
  611. int shift;
  612. int current_compass_matrix[NINE_ELEM];
  613. for (i = 0; i < THREE_AXES; i++)
  614. for (j = 0; j < THREE_AXES; j++)
  615. trans[THREE_AXES * j + i] = m[THREE_AXES * i + j];
  616. switch (s->secondary_state.compass_slave_id)
  617. {
  618. #if (MEMS_CHIP == HW_ICM20648)
  619. case HW_AK8972:
  620. scale = DATA_AKM8972_SCALE;
  621. shift = AK89XX_SHIFT;
  622. break;
  623. case HW_AK8975:
  624. scale = DATA_AKM8975_SCALE;
  625. shift = AK89XX_SHIFT;
  626. break;
  627. case HW_AK8963:
  628. scale = DATA_AKM8963_SCALE1;
  629. shift = AK89XX_SHIFT;
  630. break;
  631. case HW_AK09911:
  632. scale = DATA_AK09911_SCALE;
  633. shift = AK99XX_SHIFT;
  634. break;
  635. case HW_AK09912:
  636. scale = DATA_AK09912_SCALE;
  637. shift = AK89XX_SHIFT;
  638. break;
  639. #else
  640. case HW_AK09916:
  641. scale = DATA_AK09916_SCALE;
  642. shift = AK89XX_SHIFT;
  643. break;
  644. #endif
  645. default:
  646. scale = DATA_AKM8963_SCALE1;
  647. shift = AK89XX_SHIFT;
  648. break;
  649. }
  650. for (i = 0; i < THREE_AXES; i++) {
  651. sens[i] = s->secondary_state.compass_sens[i] + 128;
  652. sens[i] = inv_icm20948_convert_mult_q30_fxp(sens[i] << shift, scale);
  653. }
  654. for (i = 0; i < NINE_ELEM; i++) {
  655. current_compass_matrix[i] = compass_m[i] * sens[i % THREE_AXES];
  656. tmp_m[i] = 0;
  657. }
  658. for (i = 0; i < THREE_AXES; i++) {
  659. for (j = 0; j < THREE_AXES; j++) {
  660. s->secondary_state.final_matrix[i * THREE_AXES + j] = 0;
  661. for (k = 0; k < THREE_AXES; k++)
  662. s->secondary_state.final_matrix[i * THREE_AXES + j] +=
  663. inv_icm20948_convert_mult_q30_fxp(s->soft_iron_matrix[i * THREE_AXES + k],
  664. current_compass_matrix[j + k * THREE_AXES]);
  665. }
  666. }
  667. for (i = 0; i < THREE_AXES; i++)
  668. for (j = 0; j < THREE_AXES; j++)
  669. for (k = 0; k < THREE_AXES; k++)
  670. tmp_m[THREE_AXES * i + j] +=
  671. trans[THREE_AXES * i + k] *
  672. s->secondary_state.final_matrix[THREE_AXES * k + j];
  673. return dmp_icm20948_set_compass_matrix(s, tmp_m);
  674. }
  675. /**
  676. * @brief Apply mounting matrix and scaling to raw compass data.
  677. * @param[in] Raw compass data
  678. * @param[in] Compensated compass data
  679. * @return 0 if successful.
  680. */
  681. int inv_icm20948_apply_raw_compass_matrix(struct inv_icm20948 * s, short *raw_data, long *compensated_out)
  682. {
  683. int i, j;
  684. long long tmp;
  685. for (i = 0; i < THREE_AXES; i++) {
  686. tmp = 0;
  687. for (j = 0; j < THREE_AXES; j++)
  688. tmp +=
  689. (long long)s->secondary_state.final_matrix[i * THREE_AXES + j] * (((int)raw_data[j]) << 16);
  690. compensated_out[i] = (long)(tmp >> 30);
  691. }
  692. return 0;
  693. }