/drivers/misc/inv_mpu/accel/lsm303a.c

https://bitbucket.org/slukk/jb-tsm-kernel-4.2 · C · 878 lines · 613 code · 86 blank · 179 comment · 75 complexity · 5acde1795161aa003b3dc749555ada95 MD5 · raw file

  1. /*
  2. $License:
  3. Copyright (C) 2011 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. * @addtogroup ACCELDL
  18. * @brief Provides the interface to setup and handle an accelerometer.
  19. *
  20. * @{
  21. * @file lsm303a.c
  22. * @brief Accelerometer setup and handling methods for ST LSM303.
  23. */
  24. /* -------------------------------------------------------------------------- */
  25. #include <linux/i2c.h>
  26. #include <linux/module.h>
  27. #include <linux/moduleparam.h>
  28. #include <linux/kernel.h>
  29. #include <linux/errno.h>
  30. #include <linux/slab.h>
  31. #include <linux/delay.h>
  32. #include "mpu-dev.h"
  33. #include <log.h>
  34. #include <linux/mpu.h>
  35. #include "mlsl.h"
  36. #include "mldl_cfg.h"
  37. #undef MPL_LOG_TAG
  38. #define MPL_LOG_TAG "MPL-acc"
  39. /* -------------------------------------------------------------------------- */
  40. /* full scale setting - register & mask */
  41. #define LIS331_CTRL_REG1 (0x20)
  42. #define LIS331_CTRL_REG2 (0x21)
  43. #define LIS331_CTRL_REG3 (0x22)
  44. #define LIS331_CTRL_REG4 (0x23)
  45. #define LIS331_CTRL_REG5 (0x24)
  46. #define LIS331_HP_FILTER_RESET (0x25)
  47. #define LIS331_REFERENCE (0x26)
  48. #define LIS331_STATUS_REG (0x27)
  49. #define LIS331_OUT_X_L (0x28)
  50. #define LIS331_OUT_X_H (0x29)
  51. #define LIS331_OUT_Y_L (0x2a)
  52. #define LIS331_OUT_Y_H (0x2b)
  53. #define LIS331_OUT_Z_L (0x2b)
  54. #define LIS331_OUT_Z_H (0x2d)
  55. #define LIS331_INT1_CFG (0x30)
  56. #define LIS331_INT1_SRC (0x31)
  57. #define LIS331_INT1_THS (0x32)
  58. #define LIS331_INT1_DURATION (0x33)
  59. #define LIS331_INT2_CFG (0x34)
  60. #define LIS331_INT2_SRC (0x35)
  61. #define LIS331_INT2_THS (0x36)
  62. #define LIS331_INT2_DURATION (0x37)
  63. #define LIS331_CTRL_MASK (0x30)
  64. #define LIS331_SLEEP_MASK (0x20)
  65. #define LIS331_MAX_DUR (0x7F)
  66. /* -------------------------------------------------------------------------- */
  67. struct lsm303dlha_config {
  68. unsigned int odr;
  69. unsigned int fsr; /** < full scale range mg */
  70. unsigned int ths; /** < Motion no-motion thseshold mg */
  71. unsigned int dur; /** < Motion no-motion duration ms */
  72. unsigned char reg_ths;
  73. unsigned char reg_dur;
  74. unsigned char ctrl_reg1;
  75. unsigned char irq_type;
  76. unsigned char mot_int1_cfg;
  77. };
  78. struct lsm303dlha_private_data {
  79. struct lsm303dlha_config suspend;
  80. struct lsm303dlha_config resume;
  81. };
  82. /* -------------------------------------------------------------------------- */
  83. static int lsm303dlha_set_ths(void *mlsl_handle,
  84. struct ext_slave_platform_data *pdata,
  85. struct lsm303dlha_config *config,
  86. int apply,
  87. long ths)
  88. {
  89. int result = INV_SUCCESS;
  90. if ((unsigned int) ths >= config->fsr)
  91. ths = (long) config->fsr - 1;
  92. if (ths < 0)
  93. ths = 0;
  94. config->ths = ths;
  95. config->reg_ths = (unsigned char)(long)((ths * 128L) / (config->fsr));
  96. MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths);
  97. if (apply)
  98. result = inv_serial_single_write(mlsl_handle, pdata->address,
  99. LIS331_INT1_THS,
  100. config->reg_ths);
  101. return result;
  102. }
  103. static int lsm303dlha_set_dur(void *mlsl_handle,
  104. struct ext_slave_platform_data *pdata,
  105. struct lsm303dlha_config *config,
  106. int apply,
  107. long dur)
  108. {
  109. int result = INV_SUCCESS;
  110. long reg_dur = (dur * config->odr) / 1000000L;
  111. config->dur = dur;
  112. if (reg_dur > LIS331_MAX_DUR)
  113. reg_dur = LIS331_MAX_DUR;
  114. config->reg_dur = (unsigned char) reg_dur;
  115. MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur);
  116. if (apply)
  117. result = inv_serial_single_write(mlsl_handle, pdata->address,
  118. LIS331_INT1_DURATION,
  119. (unsigned char)reg_dur);
  120. return result;
  121. }
  122. /**
  123. * Sets the IRQ to fire when one of the IRQ events occur. Threshold and
  124. * duration will not be used uless the type is MOT or NMOT.
  125. *
  126. * @param config configuration to apply to, suspend or resume
  127. * @param irq_type The type of IRQ. Valid values are
  128. * - MPU_SLAVE_IRQ_TYPE_NONE
  129. * - MPU_SLAVE_IRQ_TYPE_MOTION
  130. * - MPU_SLAVE_IRQ_TYPE_DATA_READY
  131. */
  132. static int lsm303dlha_set_irq(void *mlsl_handle,
  133. struct ext_slave_platform_data *pdata,
  134. struct lsm303dlha_config *config,
  135. int apply,
  136. long irq_type)
  137. {
  138. int result = INV_SUCCESS;
  139. unsigned char reg1;
  140. unsigned char reg2;
  141. config->irq_type = (unsigned char)irq_type;
  142. if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
  143. reg1 = 0x02;
  144. reg2 = 0x00;
  145. } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) {
  146. reg1 = 0x00;
  147. reg2 = config->mot_int1_cfg;
  148. } else {
  149. reg1 = 0x00;
  150. reg2 = 0x00;
  151. }
  152. if (apply) {
  153. result = inv_serial_single_write(mlsl_handle, pdata->address,
  154. LIS331_CTRL_REG3, reg1);
  155. result = inv_serial_single_write(mlsl_handle, pdata->address,
  156. LIS331_INT1_CFG, reg2);
  157. }
  158. return result;
  159. }
  160. /**
  161. * @brief Set the output data rate for the particular configuration.
  162. *
  163. * @param mlsl_handle
  164. * the handle to the serial channel the device is connected to.
  165. * @param pdata
  166. * a pointer to the slave platform data.
  167. * @param config
  168. * Config to modify with new ODR.
  169. * @param apply
  170. * whether to apply immediately or save the settings to be applied
  171. * at the next resume.
  172. * @param odr
  173. * Output data rate in units of 1/1000Hz (mHz).
  174. *
  175. * @return INV_SUCCESS if successful or a non-zero error code.
  176. */
  177. static int lsm303dlha_set_odr(void *mlsl_handle,
  178. struct ext_slave_platform_data *pdata,
  179. struct lsm303dlha_config *config,
  180. int apply,
  181. long odr)
  182. {
  183. unsigned char bits;
  184. int result = INV_SUCCESS;
  185. if (odr > 400000) {
  186. config->odr = 1000000;
  187. bits = 0x38;
  188. } else if (odr > 100000) {
  189. config->odr = 400000;
  190. bits = 0x30;
  191. } else if (odr > 50000) {
  192. config->odr = 100000;
  193. bits = 0x28;
  194. } else if (odr > 10000) {
  195. config->odr = 50000;
  196. bits = 0x20;
  197. } else if (odr > 5000) {
  198. config->odr = 10000;
  199. bits = 0xC0;
  200. } else if (odr > 2000) {
  201. config->odr = 5000;
  202. bits = 0xB0;
  203. } else if (odr > 1000) {
  204. config->odr = 2000;
  205. bits = 0x80;
  206. } else if (odr > 500) {
  207. config->odr = 1000;
  208. bits = 0x60;
  209. } else if (odr > 0) {
  210. config->odr = 500;
  211. bits = 0x40;
  212. } else {
  213. config->odr = 0;
  214. bits = 0;
  215. }
  216. config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0x7);
  217. lsm303dlha_set_dur(mlsl_handle, pdata,
  218. config, apply, config->dur);
  219. MPL_LOGV("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1);
  220. if (apply)
  221. result = inv_serial_single_write(mlsl_handle, pdata->address,
  222. LIS331_CTRL_REG1,
  223. config->ctrl_reg1);
  224. return result;
  225. }
  226. /**
  227. * @brief Set the full scale range of the accels
  228. *
  229. * @param mlsl_handle
  230. * the handle to the serial channel the device is connected to.
  231. * @param pdata
  232. * a pointer to the slave platform data.
  233. * @param config
  234. * pointer to configuration.
  235. * @param apply
  236. * whether to apply immediately or save the settings to be applied
  237. * at the next resume.
  238. * @param fsr
  239. * requested full scale range.
  240. *
  241. * @return INV_SUCCESS if successful or a non-zero error code.
  242. */
  243. static int lsm303dlha_set_fsr(void *mlsl_handle,
  244. struct ext_slave_platform_data *pdata,
  245. struct lsm303dlha_config *config,
  246. int apply,
  247. long fsr)
  248. {
  249. unsigned char reg1 = 0x40;
  250. int result = INV_SUCCESS;
  251. if (fsr <= 2048) {
  252. config->fsr = 2048;
  253. } else if (fsr <= 4096) {
  254. reg1 |= 0x30;
  255. config->fsr = 4096;
  256. } else {
  257. reg1 |= 0x10;
  258. config->fsr = 8192;
  259. }
  260. lsm303dlha_set_ths(mlsl_handle, pdata,
  261. config, apply, config->ths);
  262. MPL_LOGV("FSR: %d\n", config->fsr);
  263. if (apply)
  264. result = inv_serial_single_write(mlsl_handle, pdata->address,
  265. LIS331_CTRL_REG4, reg1);
  266. return result;
  267. }
  268. /**
  269. * @brief suspends the device to put it in its lowest power mode.
  270. *
  271. * @param mlsl_handle
  272. * the handle to the serial channel the device is connected to.
  273. * @param slave
  274. * a pointer to the slave descriptor data structure.
  275. * @param pdata
  276. * a pointer to the slave platform data.
  277. *
  278. * @return INV_SUCCESS if successful or a non-zero error code.
  279. */
  280. static int lsm303dlha_suspend(void *mlsl_handle,
  281. struct ext_slave_descr *slave,
  282. struct ext_slave_platform_data *pdata)
  283. {
  284. int result = INV_SUCCESS;
  285. unsigned char reg1;
  286. unsigned char reg2;
  287. struct lsm303dlha_private_data *private_data =
  288. (struct lsm303dlha_private_data *)(pdata->private_data);
  289. result = inv_serial_single_write(mlsl_handle, pdata->address,
  290. LIS331_CTRL_REG1,
  291. private_data->suspend.ctrl_reg1);
  292. result = inv_serial_single_write(mlsl_handle, pdata->address,
  293. LIS331_CTRL_REG2, 0x0f);
  294. reg1 = 0x40;
  295. if (private_data->suspend.fsr == 8192)
  296. reg1 |= 0x30;
  297. else if (private_data->suspend.fsr == 4096)
  298. reg1 |= 0x10;
  299. /* else bits [4..5] are already zero */
  300. result = inv_serial_single_write(mlsl_handle, pdata->address,
  301. LIS331_CTRL_REG4, reg1);
  302. result = inv_serial_single_write(mlsl_handle, pdata->address,
  303. LIS331_INT1_THS,
  304. private_data->suspend.reg_ths);
  305. result = inv_serial_single_write(mlsl_handle, pdata->address,
  306. LIS331_INT1_DURATION,
  307. private_data->suspend.reg_dur);
  308. if (private_data->suspend.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
  309. reg1 = 0x02;
  310. reg2 = 0x00;
  311. } else if (private_data->suspend.irq_type ==
  312. MPU_SLAVE_IRQ_TYPE_MOTION) {
  313. reg1 = 0x00;
  314. reg2 = private_data->suspend.mot_int1_cfg;
  315. } else {
  316. reg1 = 0x00;
  317. reg2 = 0x00;
  318. }
  319. result = inv_serial_single_write(mlsl_handle, pdata->address,
  320. LIS331_CTRL_REG3, reg1);
  321. result = inv_serial_single_write(mlsl_handle, pdata->address,
  322. LIS331_INT1_CFG, reg2);
  323. result = inv_serial_read(mlsl_handle, pdata->address,
  324. LIS331_HP_FILTER_RESET, 1, &reg1);
  325. return result;
  326. }
  327. /**
  328. * @brief resume the device in the proper power state given the configuration
  329. * chosen.
  330. *
  331. * @param mlsl_handle
  332. * the handle to the serial channel the device is connected to.
  333. * @param slave
  334. * a pointer to the slave descriptor data structure.
  335. * @param pdata
  336. * a pointer to the slave platform data.
  337. *
  338. * @return INV_SUCCESS if successful or a non-zero error code.
  339. */
  340. static int lsm303dlha_resume(void *mlsl_handle,
  341. struct ext_slave_descr *slave,
  342. struct ext_slave_platform_data *pdata)
  343. {
  344. int result = INV_SUCCESS;
  345. unsigned char reg1;
  346. unsigned char reg2;
  347. struct lsm303dlha_private_data *private_data =
  348. (struct lsm303dlha_private_data *)(pdata->private_data);
  349. result = inv_serial_single_write(mlsl_handle, pdata->address,
  350. LIS331_CTRL_REG1,
  351. private_data->resume.ctrl_reg1);
  352. if (result) {
  353. LOG_RESULT_LOCATION(result);
  354. return result;
  355. }
  356. msleep(6);
  357. /* Full Scale */
  358. reg1 = 0x40;
  359. if (private_data->resume.fsr == 8192)
  360. reg1 |= 0x30;
  361. else if (private_data->resume.fsr == 4096)
  362. reg1 |= 0x10;
  363. result = inv_serial_single_write(mlsl_handle, pdata->address,
  364. LIS331_CTRL_REG4, reg1);
  365. if (result) {
  366. LOG_RESULT_LOCATION(result);
  367. return result;
  368. }
  369. /* Configure high pass filter */
  370. result = inv_serial_single_write(mlsl_handle, pdata->address,
  371. LIS331_CTRL_REG2, 0x0F);
  372. if (result) {
  373. LOG_RESULT_LOCATION(result);
  374. return result;
  375. }
  376. if (private_data->resume.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
  377. reg1 = 0x02;
  378. reg2 = 0x00;
  379. } else if (private_data->resume.irq_type ==
  380. MPU_SLAVE_IRQ_TYPE_MOTION) {
  381. reg1 = 0x00;
  382. reg2 = private_data->resume.mot_int1_cfg;
  383. } else {
  384. reg1 = 0x00;
  385. reg2 = 0x00;
  386. }
  387. result = inv_serial_single_write(mlsl_handle, pdata->address,
  388. LIS331_CTRL_REG3, reg1);
  389. if (result) {
  390. LOG_RESULT_LOCATION(result);
  391. return result;
  392. }
  393. result = inv_serial_single_write(mlsl_handle, pdata->address,
  394. LIS331_INT1_THS,
  395. private_data->resume.reg_ths);
  396. if (result) {
  397. LOG_RESULT_LOCATION(result);
  398. return result;
  399. }
  400. result = inv_serial_single_write(mlsl_handle, pdata->address,
  401. LIS331_INT1_DURATION,
  402. private_data->resume.reg_dur);
  403. if (result) {
  404. LOG_RESULT_LOCATION(result);
  405. return result;
  406. }
  407. result = inv_serial_single_write(mlsl_handle, pdata->address,
  408. LIS331_INT1_CFG, reg2);
  409. if (result) {
  410. LOG_RESULT_LOCATION(result);
  411. return result;
  412. }
  413. result = inv_serial_read(mlsl_handle, pdata->address,
  414. LIS331_HP_FILTER_RESET, 1, &reg1);
  415. if (result) {
  416. LOG_RESULT_LOCATION(result);
  417. return result;
  418. }
  419. return result;
  420. }
  421. /**
  422. * @brief read the sensor data from the device.
  423. *
  424. * @param mlsl_handle
  425. * the handle to the serial channel the device is connected to.
  426. * @param slave
  427. * a pointer to the slave descriptor data structure.
  428. * @param pdata
  429. * a pointer to the slave platform data.
  430. * @param data
  431. * a buffer to store the data read.
  432. *
  433. * @return INV_SUCCESS if successful or a non-zero error code.
  434. */
  435. static int lsm303dlha_read(void *mlsl_handle,
  436. struct ext_slave_descr *slave,
  437. struct ext_slave_platform_data *pdata,
  438. unsigned char *data)
  439. {
  440. int result = INV_SUCCESS;
  441. result = inv_serial_read(mlsl_handle, pdata->address,
  442. LIS331_STATUS_REG, 1, data);
  443. if (data[0] & 0x0F) {
  444. result = inv_serial_read(mlsl_handle, pdata->address,
  445. slave->read_reg, slave->read_len, data);
  446. return result;
  447. } else
  448. return INV_ERROR_ACCEL_DATA_NOT_READY;
  449. }
  450. /**
  451. * @brief one-time device driver initialization function.
  452. * If the driver is built as a kernel module, this function will be
  453. * called when the module is loaded in the kernel.
  454. * If the driver is built-in in the kernel, this function will be
  455. * called at boot time.
  456. *
  457. * @param mlsl_handle
  458. * the handle to the serial channel the device is connected to.
  459. * @param slave
  460. * a pointer to the slave descriptor data structure.
  461. * @param pdata
  462. * a pointer to the slave platform data.
  463. *
  464. * @return INV_SUCCESS if successful or a non-zero error code.
  465. */
  466. static int lsm303dlha_init(void *mlsl_handle,
  467. struct ext_slave_descr *slave,
  468. struct ext_slave_platform_data *pdata)
  469. {
  470. long range;
  471. struct lsm303dlha_private_data *private_data;
  472. private_data = (struct lsm303dlha_private_data *)
  473. kzalloc(sizeof(struct lsm303dlha_private_data), GFP_KERNEL);
  474. if (!private_data)
  475. return INV_ERROR_MEMORY_EXAUSTED;
  476. pdata->private_data = private_data;
  477. private_data->resume.ctrl_reg1 = 0x37;
  478. private_data->suspend.ctrl_reg1 = 0x47;
  479. private_data->resume.mot_int1_cfg = 0x95;
  480. private_data->suspend.mot_int1_cfg = 0x2a;
  481. lsm303dlha_set_odr(mlsl_handle, pdata, &private_data->suspend,
  482. FALSE, 0);
  483. lsm303dlha_set_odr(mlsl_handle, pdata, &private_data->resume,
  484. FALSE, 200000);
  485. range = range_fixedpoint_to_long_mg(slave->range);
  486. lsm303dlha_set_fsr(mlsl_handle, pdata, &private_data->suspend,
  487. FALSE, range);
  488. lsm303dlha_set_fsr(mlsl_handle, pdata, &private_data->resume,
  489. FALSE, range);
  490. lsm303dlha_set_ths(mlsl_handle, pdata, &private_data->suspend,
  491. FALSE, 80);
  492. lsm303dlha_set_ths(mlsl_handle, pdata, &private_data->resume,
  493. FALSE, 40);
  494. lsm303dlha_set_dur(mlsl_handle, pdata, &private_data->suspend,
  495. FALSE, 1000);
  496. lsm303dlha_set_dur(mlsl_handle, pdata, &private_data->resume,
  497. FALSE, 2540);
  498. lsm303dlha_set_irq(mlsl_handle, pdata, &private_data->suspend,
  499. FALSE, MPU_SLAVE_IRQ_TYPE_NONE);
  500. lsm303dlha_set_irq(mlsl_handle, pdata, &private_data->resume,
  501. FALSE, MPU_SLAVE_IRQ_TYPE_NONE);
  502. return INV_SUCCESS;
  503. }
  504. /**
  505. * @brief one-time device driver exit function.
  506. * If the driver is built as a kernel module, this function will be
  507. * called when the module is removed from the kernel.
  508. *
  509. * @param mlsl_handle
  510. * the handle to the serial channel the device is connected to.
  511. * @param slave
  512. * a pointer to the slave descriptor data structure.
  513. * @param pdata
  514. * a pointer to the slave platform data.
  515. *
  516. * @return INV_SUCCESS if successful or a non-zero error code.
  517. */
  518. static int lsm303dlha_exit(void *mlsl_handle,
  519. struct ext_slave_descr *slave,
  520. struct ext_slave_platform_data *pdata)
  521. {
  522. kfree(pdata->private_data);
  523. return INV_SUCCESS;
  524. }
  525. /**
  526. * @brief device configuration facility.
  527. *
  528. * @param mlsl_handle
  529. * the handle to the serial channel the device is connected to.
  530. * @param slave
  531. * a pointer to the slave descriptor data structure.
  532. * @param pdata
  533. * a pointer to the slave platform data.
  534. * @param data
  535. * a pointer to the configuration data structure.
  536. *
  537. * @return INV_SUCCESS if successful or a non-zero error code.
  538. */
  539. static int lsm303dlha_config(void *mlsl_handle,
  540. struct ext_slave_descr *slave,
  541. struct ext_slave_platform_data *pdata,
  542. struct ext_slave_config *data)
  543. {
  544. struct lsm303dlha_private_data *private_data = pdata->private_data;
  545. if (!data->data)
  546. return INV_ERROR_INVALID_PARAMETER;
  547. switch (data->key) {
  548. case MPU_SLAVE_CONFIG_ODR_SUSPEND:
  549. return lsm303dlha_set_odr(mlsl_handle, pdata,
  550. &private_data->suspend,
  551. data->apply,
  552. *((long *)data->data));
  553. case MPU_SLAVE_CONFIG_ODR_RESUME:
  554. return lsm303dlha_set_odr(mlsl_handle, pdata,
  555. &private_data->resume,
  556. data->apply,
  557. *((long *)data->data));
  558. case MPU_SLAVE_CONFIG_FSR_SUSPEND:
  559. return lsm303dlha_set_fsr(mlsl_handle, pdata,
  560. &private_data->suspend,
  561. data->apply,
  562. *((long *)data->data));
  563. case MPU_SLAVE_CONFIG_FSR_RESUME:
  564. return lsm303dlha_set_fsr(mlsl_handle, pdata,
  565. &private_data->resume,
  566. data->apply,
  567. *((long *)data->data));
  568. case MPU_SLAVE_CONFIG_MOT_THS:
  569. return lsm303dlha_set_ths(mlsl_handle, pdata,
  570. &private_data->suspend,
  571. data->apply,
  572. *((long *)data->data));
  573. case MPU_SLAVE_CONFIG_NMOT_THS:
  574. return lsm303dlha_set_ths(mlsl_handle, pdata,
  575. &private_data->resume,
  576. data->apply,
  577. *((long *)data->data));
  578. case MPU_SLAVE_CONFIG_MOT_DUR:
  579. return lsm303dlha_set_dur(mlsl_handle, pdata,
  580. &private_data->suspend,
  581. data->apply,
  582. *((long *)data->data));
  583. case MPU_SLAVE_CONFIG_NMOT_DUR:
  584. return lsm303dlha_set_dur(mlsl_handle, pdata,
  585. &private_data->resume,
  586. data->apply,
  587. *((long *)data->data));
  588. case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
  589. return lsm303dlha_set_irq(mlsl_handle, pdata,
  590. &private_data->suspend,
  591. data->apply,
  592. *((long *)data->data));
  593. case MPU_SLAVE_CONFIG_IRQ_RESUME:
  594. return lsm303dlha_set_irq(mlsl_handle, pdata,
  595. &private_data->resume,
  596. data->apply,
  597. *((long *)data->data));
  598. default:
  599. LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED);
  600. return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
  601. };
  602. return INV_SUCCESS;
  603. }
  604. /**
  605. * @brief facility to retrieve the device configuration.
  606. *
  607. * @param mlsl_handle
  608. * the handle to the serial channel the device is connected to.
  609. * @param slave
  610. * a pointer to the slave descriptor data structure.
  611. * @param pdata
  612. * a pointer to the slave platform data.
  613. * @param data
  614. * a pointer to store the returned configuration data structure.
  615. *
  616. * @return INV_SUCCESS if successful or a non-zero error code.
  617. */
  618. static int lsm303dlha_get_config(void *mlsl_handle,
  619. struct ext_slave_descr *slave,
  620. struct ext_slave_platform_data *pdata,
  621. struct ext_slave_config *data)
  622. {
  623. struct lsm303dlha_private_data *private_data = pdata->private_data;
  624. if (!data->data)
  625. return INV_ERROR_INVALID_PARAMETER;
  626. switch (data->key) {
  627. case MPU_SLAVE_CONFIG_ODR_SUSPEND:
  628. (*(unsigned long *)data->data) =
  629. (unsigned long) private_data->suspend.odr;
  630. break;
  631. case MPU_SLAVE_CONFIG_ODR_RESUME:
  632. (*(unsigned long *)data->data) =
  633. (unsigned long) private_data->resume.odr;
  634. break;
  635. case MPU_SLAVE_CONFIG_FSR_SUSPEND:
  636. (*(unsigned long *)data->data) =
  637. (unsigned long) private_data->suspend.fsr;
  638. break;
  639. case MPU_SLAVE_CONFIG_FSR_RESUME:
  640. (*(unsigned long *)data->data) =
  641. (unsigned long) private_data->resume.fsr;
  642. break;
  643. case MPU_SLAVE_CONFIG_MOT_THS:
  644. (*(unsigned long *)data->data) =
  645. (unsigned long) private_data->suspend.ths;
  646. break;
  647. case MPU_SLAVE_CONFIG_NMOT_THS:
  648. (*(unsigned long *)data->data) =
  649. (unsigned long) private_data->resume.ths;
  650. break;
  651. case MPU_SLAVE_CONFIG_MOT_DUR:
  652. (*(unsigned long *)data->data) =
  653. (unsigned long) private_data->suspend.dur;
  654. break;
  655. case MPU_SLAVE_CONFIG_NMOT_DUR:
  656. (*(unsigned long *)data->data) =
  657. (unsigned long) private_data->resume.dur;
  658. break;
  659. case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
  660. (*(unsigned long *)data->data) =
  661. (unsigned long) private_data->suspend.irq_type;
  662. break;
  663. case MPU_SLAVE_CONFIG_IRQ_RESUME:
  664. (*(unsigned long *)data->data) =
  665. (unsigned long) private_data->resume.irq_type;
  666. break;
  667. default:
  668. LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED);
  669. return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
  670. };
  671. return INV_SUCCESS;
  672. }
  673. static struct ext_slave_descr lsm303dlha_descr = {
  674. .init = lsm303dlha_init,
  675. .exit = lsm303dlha_exit,
  676. .suspend = lsm303dlha_suspend,
  677. .resume = lsm303dlha_resume,
  678. .read = lsm303dlha_read,
  679. .config = lsm303dlha_config,
  680. .get_config = lsm303dlha_get_config,
  681. .name = "lsm303dlha",
  682. .type = EXT_SLAVE_TYPE_ACCELEROMETER,
  683. .id = ACCEL_ID_LSM303A,
  684. .read_reg = (0x28 | 0x80), /* 0x80 for burst reads */
  685. .read_len = 6,
  686. .endian = EXT_SLAVE_BIG_ENDIAN,
  687. .range = {2, 480},
  688. .trigger = NULL,
  689. };
  690. static
  691. struct ext_slave_descr *lsm303a_get_slave_descr(void)
  692. {
  693. return &lsm303dlha_descr;
  694. }
  695. /* -------------------------------------------------------------------------- */
  696. struct lsm303a_mod_private_data {
  697. struct i2c_client *client;
  698. struct ext_slave_platform_data *pdata;
  699. };
  700. static unsigned short normal_i2c[] = { I2C_CLIENT_END };
  701. static int lsm303a_mod_probe(struct i2c_client *client,
  702. const struct i2c_device_id *devid)
  703. {
  704. struct ext_slave_platform_data *pdata;
  705. struct lsm303a_mod_private_data *private_data;
  706. int result = 0;
  707. dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
  708. if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
  709. result = -ENODEV;
  710. goto out_no_free;
  711. }
  712. pdata = client->dev.platform_data;
  713. if (!pdata) {
  714. dev_err(&client->adapter->dev,
  715. "Missing platform data for slave %s\n", devid->name);
  716. result = -EFAULT;
  717. goto out_no_free;
  718. }
  719. private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
  720. if (!private_data) {
  721. result = -ENOMEM;
  722. goto out_no_free;
  723. }
  724. i2c_set_clientdata(client, private_data);
  725. private_data->client = client;
  726. private_data->pdata = pdata;
  727. result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
  728. lsm303a_get_slave_descr);
  729. if (result) {
  730. dev_err(&client->adapter->dev,
  731. "Slave registration failed: %s, %d\n",
  732. devid->name, result);
  733. goto out_free_memory;
  734. }
  735. return result;
  736. out_free_memory:
  737. kfree(private_data);
  738. out_no_free:
  739. dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
  740. return result;
  741. }
  742. static int lsm303a_mod_remove(struct i2c_client *client)
  743. {
  744. struct lsm303a_mod_private_data *private_data =
  745. i2c_get_clientdata(client);
  746. dev_dbg(&client->adapter->dev, "%s\n", __func__);
  747. inv_mpu_unregister_slave(client, private_data->pdata,
  748. lsm303a_get_slave_descr);
  749. kfree(private_data);
  750. return 0;
  751. }
  752. static const struct i2c_device_id lsm303a_mod_id[] = {
  753. { "lsm303a", ACCEL_ID_LSM303A },
  754. {}
  755. };
  756. MODULE_DEVICE_TABLE(i2c, lsm303a_mod_id);
  757. static struct i2c_driver lsm303a_mod_driver = {
  758. .class = I2C_CLASS_HWMON,
  759. .probe = lsm303a_mod_probe,
  760. .remove = lsm303a_mod_remove,
  761. .id_table = lsm303a_mod_id,
  762. .driver = {
  763. .owner = THIS_MODULE,
  764. .name = "lsm303a_mod",
  765. },
  766. .address_list = normal_i2c,
  767. };
  768. static int __init lsm303a_mod_init(void)
  769. {
  770. int res = i2c_add_driver(&lsm303a_mod_driver);
  771. pr_info("%s: Probe name %s\n", __func__, "lsm303a_mod");
  772. if (res)
  773. pr_err("%s failed\n", __func__);
  774. return res;
  775. }
  776. static void __exit lsm303a_mod_exit(void)
  777. {
  778. pr_info("%s\n", __func__);
  779. i2c_del_driver(&lsm303a_mod_driver);
  780. }
  781. module_init(lsm303a_mod_init);
  782. module_exit(lsm303a_mod_exit);
  783. MODULE_AUTHOR("Invensense Corporation");
  784. MODULE_DESCRIPTION("Driver to integrate LSM303A sensor with the MPU");
  785. MODULE_LICENSE("GPL");
  786. MODULE_ALIAS("lsm303a_mod");
  787. /**
  788. * @}
  789. */