hmc5883.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. $License:
  3. Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. $
  15. */
  16. /**
  17. * @brief Provides the interface to setup and handle a compass
  18. * connected to the primary I2C interface of the gyroscope.
  19. *
  20. * @{
  21. * @file hmc5883.c
  22. * @brief Magnetometer setup and handling methods for honeywell hmc5883
  23. * compass.
  24. */
  25. /* ------------------ */
  26. /* - Include Files. - */
  27. /* ------------------ */
  28. #ifdef __KERNEL__
  29. #include <linux/module.h>
  30. #endif
  31. #include "mpu.h"
  32. #include "mlsl.h"
  33. #include "mlos.h"
  34. #include <log.h>
  35. #undef MPL_LOG_TAG
  36. #define MPL_LOG_TAG "MPL-compass"
  37. /*-----HONEYWELL HMC5883 Registers ------*/
  38. enum HMC_REG {
  39. HMC_REG_CONF_A = 0x0,
  40. HMC_REG_CONF_B = 0x1,
  41. HMC_REG_MODE = 0x2,
  42. HMC_REG_X_M = 0x3,
  43. HMC_REG_X_L = 0x4,
  44. HMC_REG_Z_M = 0x5,
  45. HMC_REG_Z_L = 0x6,
  46. HMC_REG_Y_M = 0x7,
  47. HMC_REG_Y_L = 0x8,
  48. HMC_REG_STATUS = 0x9,
  49. HMC_REG_ID_A = 0xA,
  50. HMC_REG_ID_B = 0xB,
  51. HMC_REG_ID_C = 0xC
  52. };
  53. enum HMC_CONF_A {
  54. HMC_CONF_A_DRATE_MASK = 0x1C,
  55. HMC_CONF_A_DRATE_0_75 = 0x00,
  56. HMC_CONF_A_DRATE_1_5 = 0x04,
  57. HMC_CONF_A_DRATE_3 = 0x08,
  58. HMC_CONF_A_DRATE_7_5 = 0x0C,
  59. HMC_CONF_A_DRATE_15 = 0x10,
  60. HMC_CONF_A_DRATE_30 = 0x14,
  61. HMC_CONF_A_DRATE_75 = 0x18,
  62. HMC_CONF_A_MEAS_MASK = 0x3,
  63. HMC_CONF_A_MEAS_NORM = 0x0,
  64. HMC_CONF_A_MEAS_POS = 0x1,
  65. HMC_CONF_A_MEAS_NEG = 0x2
  66. };
  67. enum HMC_CONF_B{
  68. HMC_CONF_B_GAIN_MASK = 0xE0,
  69. HMC_CONF_B_GAIN_0_9 = 0x00,
  70. HMC_CONF_B_GAIN_1_2 = 0x20,
  71. HMC_CONF_B_GAIN_1_9 = 0x40,
  72. HMC_CONF_B_GAIN_2_5 = 0x60,
  73. HMC_CONF_B_GAIN_4_0 = 0x80,
  74. HMC_CONF_B_GAIN_4_6 = 0xA0,
  75. HMC_CONF_B_GAIN_5_5 = 0xC0,
  76. HMC_CONF_B_GAIN_7_9 = 0xE0
  77. };
  78. enum HMC_MODE {
  79. HMC_MODE_MASK = 0x3,
  80. HMC_MODE_CONT = 0x0,
  81. HMC_MODE_SINGLE = 0x1,
  82. HMC_MODE_IDLE = 0x2,
  83. HMC_MODE_SLEEP = 0x3
  84. };
  85. /* --------------------- */
  86. /* - Variables. - */
  87. /* --------------------- */
  88. /*****************************************
  89. Accelerometer Initialization Functions
  90. *****************************************/
  91. int hmc5883_suspend(void *mlsl_handle,
  92. struct ext_slave_descr *slave,
  93. struct ext_slave_platform_data *pdata)
  94. {
  95. int result = ML_SUCCESS;
  96. result =
  97. MLSLSerialWriteSingle(mlsl_handle, pdata->address,
  98. HMC_REG_MODE, HMC_MODE_SLEEP);
  99. ERROR_CHECK(result);
  100. MLOSSleep(3);
  101. return result;
  102. }
  103. int hmc5883_resume(void *mlsl_handle,
  104. struct ext_slave_descr *slave,
  105. struct ext_slave_platform_data *pdata)
  106. {
  107. int result = ML_SUCCESS;
  108. /* Use single measurement mode. Start at sleep state. */
  109. result =
  110. MLSLSerialWriteSingle(mlsl_handle, pdata->address,
  111. HMC_REG_MODE, HMC_MODE_SLEEP);
  112. ERROR_CHECK(result);
  113. /* Config normal measurement */
  114. result =
  115. MLSLSerialWriteSingle(mlsl_handle, pdata->address,
  116. HMC_REG_CONF_A, 0);
  117. ERROR_CHECK(result);
  118. /* Adjust gain to 307 LSB/Gauss */
  119. result =
  120. MLSLSerialWriteSingle(mlsl_handle, pdata->address,
  121. HMC_REG_CONF_B, HMC_CONF_B_GAIN_5_5);
  122. ERROR_CHECK(result);
  123. return result;
  124. }
  125. int hmc5883_read(void *mlsl_handle,
  126. struct ext_slave_descr *slave,
  127. struct ext_slave_platform_data *pdata,
  128. unsigned char *data)
  129. {
  130. unsigned char stat;
  131. tMLError result = ML_SUCCESS;
  132. unsigned char tmp;
  133. short axisFixed;
  134. /* Read status reg. to check if data is ready */
  135. result =
  136. MLSLSerialRead(mlsl_handle, pdata->address, HMC_REG_STATUS, 1,
  137. &stat);
  138. ERROR_CHECK(result);
  139. if (stat & 0x01) {
  140. result =
  141. MLSLSerialRead(mlsl_handle, pdata->address,
  142. HMC_REG_X_M, 6, (unsigned char *) data);
  143. ERROR_CHECK(result);
  144. /* switch YZ axis to proper position */
  145. tmp = data[2];
  146. data[2] = data[4];
  147. data[4] = tmp;
  148. tmp = data[3];
  149. data[3] = data[5];
  150. data[5] = tmp;
  151. /*drop data if overflows */
  152. if ((data[0] == 0xf0) || (data[2] == 0xf0)
  153. || (data[4] == 0xf0)) {
  154. /* trigger next measurement read */
  155. result =
  156. MLSLSerialWriteSingle(mlsl_handle,
  157. pdata->address,
  158. HMC_REG_MODE,
  159. HMC_MODE_SINGLE);
  160. ERROR_CHECK(result);
  161. return ML_ERROR_COMPASS_DATA_OVERFLOW;
  162. }
  163. /* convert to fixed point and apply sensitivity correction for
  164. Z-axis */
  165. axisFixed =
  166. (short) ((unsigned short) data[5] +
  167. (unsigned short) data[4] * 256);
  168. /* scale up by 1.125 (36/32) */
  169. axisFixed = (short) (axisFixed * 36);
  170. data[4] = axisFixed >> 8;
  171. data[5] = axisFixed & 0xFF;
  172. axisFixed =
  173. (short) ((unsigned short) data[3] +
  174. (unsigned short) data[2] * 256);
  175. axisFixed = (short) (axisFixed * 32);
  176. data[2] = axisFixed >> 8;
  177. data[3] = axisFixed & 0xFF;
  178. axisFixed =
  179. (short) ((unsigned short) data[1] +
  180. (unsigned short) data[0] * 256);
  181. axisFixed = (short) (axisFixed * 32);
  182. data[0] = axisFixed >> 8;
  183. data[1] = axisFixed & 0xFF;
  184. /* trigger next measurement read */
  185. result =
  186. MLSLSerialWriteSingle(mlsl_handle, pdata->address,
  187. HMC_REG_MODE, HMC_MODE_SINGLE);
  188. ERROR_CHECK(result);
  189. return ML_SUCCESS;
  190. } else {
  191. /* trigger next measurement read */
  192. result =
  193. MLSLSerialWriteSingle(mlsl_handle, pdata->address,
  194. HMC_REG_MODE, HMC_MODE_SINGLE);
  195. ERROR_CHECK(result);
  196. return ML_ERROR_COMPASS_DATA_NOT_READY;
  197. }
  198. }
  199. struct ext_slave_descr hmc5883_descr = {
  200. /*.init = */ NULL,
  201. /*.exit = */ NULL,
  202. /*.suspend = */ hmc5883_suspend,
  203. /*.resume = */ hmc5883_resume,
  204. /*.read = */ hmc5883_read,
  205. /*.config = */ NULL,
  206. /*.get_config = */ NULL,
  207. /*.name = */ "hmc5883",
  208. /*.type = */ EXT_SLAVE_TYPE_COMPASS,
  209. /*.id = */ COMPASS_ID_HMC5883,
  210. /*.reg = */ 0x06,
  211. /*.len = */ 6,
  212. /*.endian = */ EXT_SLAVE_BIG_ENDIAN,
  213. /*.range = */ {10673, 6156},
  214. };
  215. struct ext_slave_descr *hmc5883_get_slave_descr(void)
  216. {
  217. return &hmc5883_descr;
  218. }
  219. EXPORT_SYMBOL(hmc5883_get_slave_descr);
  220. /**
  221. * @}
  222. **/