inv_mpu_aux.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2019 TDK-InvenSense, Inc.
  4. */
  5. #include <linux/kernel.h>
  6. #include <linux/device.h>
  7. #include <linux/regmap.h>
  8. #include <linux/delay.h>
  9. #include "inv_mpu_aux.h"
  10. #include "inv_mpu_iio.h"
  11. /*
  12. * i2c master auxiliary bus transfer function.
  13. * Requires the i2c operations to be correctly setup before.
  14. */
  15. static int inv_mpu_i2c_master_xfer(const struct inv_mpu6050_state *st)
  16. {
  17. /* use 50hz frequency for xfer */
  18. const unsigned int freq = 50;
  19. const unsigned int period_ms = 1000 / freq;
  20. uint8_t d;
  21. unsigned int user_ctrl;
  22. int ret;
  23. /* set sample rate */
  24. d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(freq);
  25. ret = regmap_write(st->map, st->reg->sample_rate_div, d);
  26. if (ret)
  27. return ret;
  28. /* start i2c master */
  29. user_ctrl = st->chip_config.user_ctrl | INV_MPU6050_BIT_I2C_MST_EN;
  30. ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
  31. if (ret)
  32. goto error_restore_rate;
  33. /* wait for xfer: 1 period + half-period margin */
  34. msleep(period_ms + period_ms / 2);
  35. /* stop i2c master */
  36. user_ctrl = st->chip_config.user_ctrl;
  37. ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
  38. if (ret)
  39. goto error_stop_i2c;
  40. /* restore sample rate */
  41. d = st->chip_config.divider;
  42. ret = regmap_write(st->map, st->reg->sample_rate_div, d);
  43. if (ret)
  44. goto error_restore_rate;
  45. return 0;
  46. error_stop_i2c:
  47. regmap_write(st->map, st->reg->user_ctrl, st->chip_config.user_ctrl);
  48. error_restore_rate:
  49. regmap_write(st->map, st->reg->sample_rate_div, st->chip_config.divider);
  50. return ret;
  51. }
  52. /**
  53. * inv_mpu_aux_init() - init i2c auxiliary bus
  54. * @st: driver internal state
  55. *
  56. * Returns 0 on success, a negative error code otherwise.
  57. */
  58. int inv_mpu_aux_init(const struct inv_mpu6050_state *st)
  59. {
  60. unsigned int val;
  61. int ret;
  62. /*
  63. * Code based on the vendor Linux kernel v3.0,
  64. * the exact meaning is unknown.
  65. */
  66. if (st->chip_type == INV_MPU9150) {
  67. unsigned int mask = BIT(7);
  68. val = st->level_shifter ? mask : 0;
  69. ret = regmap_update_bits(st->map, 0x1, mask, val);
  70. if (ret)
  71. return ret;
  72. }
  73. /* configure i2c master */
  74. val = INV_MPU6050_BITS_I2C_MST_CLK_400KHZ |
  75. INV_MPU6050_BIT_WAIT_FOR_ES;
  76. ret = regmap_write(st->map, INV_MPU6050_REG_I2C_MST_CTRL, val);
  77. if (ret)
  78. return ret;
  79. /* configure i2c master delay */
  80. ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV4_CTRL, 0);
  81. if (ret)
  82. return ret;
  83. val = INV_MPU6050_BIT_I2C_SLV0_DLY_EN |
  84. INV_MPU6050_BIT_I2C_SLV1_DLY_EN |
  85. INV_MPU6050_BIT_I2C_SLV2_DLY_EN |
  86. INV_MPU6050_BIT_I2C_SLV3_DLY_EN |
  87. INV_MPU6050_BIT_DELAY_ES_SHADOW;
  88. return regmap_write(st->map, INV_MPU6050_REG_I2C_MST_DELAY_CTRL, val);
  89. }
  90. /**
  91. * inv_mpu_aux_read() - read register function for i2c auxiliary bus
  92. * @st: driver internal state.
  93. * @addr: chip i2c Address
  94. * @reg: chip register address
  95. * @val: buffer for storing read bytes
  96. * @size: number of bytes to read
  97. *
  98. * Returns 0 on success, a negative error code otherwise.
  99. */
  100. int inv_mpu_aux_read(const struct inv_mpu6050_state *st, uint8_t addr,
  101. uint8_t reg, uint8_t *val, size_t size)
  102. {
  103. unsigned int status;
  104. int ret;
  105. if (size > 0x0F)
  106. return -EINVAL;
  107. /* setup i2c SLV0 control: i2c addr, register, enable + size */
  108. ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0),
  109. INV_MPU6050_BIT_I2C_SLV_RNW | addr);
  110. if (ret)
  111. return ret;
  112. ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0), reg);
  113. if (ret)
  114. return ret;
  115. ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0),
  116. INV_MPU6050_BIT_SLV_EN | size);
  117. if (ret)
  118. return ret;
  119. /* do i2c xfer */
  120. ret = inv_mpu_i2c_master_xfer(st);
  121. if (ret)
  122. goto error_disable_i2c;
  123. /* disable i2c slave */
  124. ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
  125. if (ret)
  126. goto error_disable_i2c;
  127. /* check i2c status */
  128. ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
  129. if (ret)
  130. return ret;
  131. if (status & INV_MPU6050_BIT_I2C_SLV0_NACK)
  132. return -EIO;
  133. /* read data in registers */
  134. return regmap_bulk_read(st->map, INV_MPU6050_REG_EXT_SENS_DATA,
  135. val, size);
  136. error_disable_i2c:
  137. regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
  138. return ret;
  139. }
  140. /**
  141. * inv_mpu_aux_write() - write register function for i2c auxiliary bus
  142. * @st: driver internal state.
  143. * @addr: chip i2c Address
  144. * @reg: chip register address
  145. * @val: 1 byte value to write
  146. *
  147. * Returns 0 on success, a negative error code otherwise.
  148. */
  149. int inv_mpu_aux_write(const struct inv_mpu6050_state *st, uint8_t addr,
  150. uint8_t reg, uint8_t val)
  151. {
  152. unsigned int status;
  153. int ret;
  154. /* setup i2c SLV0 control: i2c addr, register, value, enable + size */
  155. ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0), addr);
  156. if (ret)
  157. return ret;
  158. ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0), reg);
  159. if (ret)
  160. return ret;
  161. ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(0), val);
  162. if (ret)
  163. return ret;
  164. ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0),
  165. INV_MPU6050_BIT_SLV_EN | 1);
  166. if (ret)
  167. return ret;
  168. /* do i2c xfer */
  169. ret = inv_mpu_i2c_master_xfer(st);
  170. if (ret)
  171. goto error_disable_i2c;
  172. /* disable i2c slave */
  173. ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
  174. if (ret)
  175. goto error_disable_i2c;
  176. /* check i2c status */
  177. ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
  178. if (ret)
  179. return ret;
  180. if (status & INV_MPU6050_BIT_I2C_SLV0_NACK)
  181. return -EIO;
  182. return 0;
  183. error_disable_i2c:
  184. regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
  185. return ret;
  186. }