DW9718AF.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. * DW9718AF voice coil motor driver
  3. *
  4. *
  5. */
  6. #include <linux/i2c.h>
  7. #include <linux/delay.h>
  8. #include <linux/uaccess.h>
  9. #include <linux/fs.h>
  10. #include "lens_info.h"
  11. #define AF_DRVNAME "DW9718AF_DRV"
  12. #define AF_I2C_SLAVE_ADDR 0x18
  13. #define AF_DEBUG
  14. #ifdef AF_DEBUG
  15. #define LOG_INF(format, args...) pr_debug(AF_DRVNAME " [%s] " format, __func__, ##args)
  16. #else
  17. #define LOG_INF(format, args...)
  18. #endif
  19. static struct i2c_client *g_pstAF_I2Cclient;
  20. static int *g_pAF_Opened;
  21. static spinlock_t *g_pAF_SpinLock;
  22. static unsigned long g_u4AF_INF;
  23. static unsigned long g_u4AF_MACRO = 1023;
  24. static unsigned long g_u4TargetPosition;
  25. static unsigned long g_u4CurrPosition;
  26. static int i2c_read(u8 a_u2Addr, u8 *a_puBuff)
  27. {
  28. int i4RetValue = 0;
  29. char puReadCmd[1] = { (char)(a_u2Addr) };
  30. i4RetValue = i2c_master_send(g_pstAF_I2Cclient, puReadCmd, 1);
  31. if (i4RetValue != 2) {
  32. LOG_INF(" I2C write failed!!\n");
  33. return -1;
  34. }
  35. i4RetValue = i2c_master_recv(g_pstAF_I2Cclient, (char *)a_puBuff, 1);
  36. if (i4RetValue != 1) {
  37. LOG_INF(" I2C read failed!!\n");
  38. return -1;
  39. }
  40. return 0;
  41. }
  42. static u8 read_data(u8 addr)
  43. {
  44. u8 get_byte = 0;
  45. i2c_read(addr, &get_byte);
  46. return get_byte;
  47. }
  48. static int s4DW9718AF_ReadReg(unsigned short *a_pu2Result)
  49. {
  50. *a_pu2Result = (read_data(0x02) << 8) + (read_data(0x03) & 0xff);
  51. return 0;
  52. }
  53. static int s4AF_WriteReg(u16 a_u2Data)
  54. {
  55. int i4RetValue = 0;
  56. char puSendCmd[3] = { 0x02, (char)(a_u2Data >> 8), (char)(a_u2Data & 0xFF) };
  57. g_pstAF_I2Cclient->addr = AF_I2C_SLAVE_ADDR;
  58. g_pstAF_I2Cclient->addr = g_pstAF_I2Cclient->addr >> 1;
  59. i4RetValue = i2c_master_send(g_pstAF_I2Cclient, puSendCmd, 3);
  60. if (i4RetValue < 0) {
  61. LOG_INF("I2C send failed!!\n");
  62. return -1;
  63. }
  64. return 0;
  65. }
  66. static inline int getAFInfo(__user stAF_MotorInfo *pstMotorInfo)
  67. {
  68. stAF_MotorInfo stMotorInfo;
  69. stMotorInfo.u4MacroPosition = g_u4AF_MACRO;
  70. stMotorInfo.u4InfPosition = g_u4AF_INF;
  71. stMotorInfo.u4CurrentPosition = g_u4CurrPosition;
  72. stMotorInfo.bIsSupportSR = 1;
  73. stMotorInfo.bIsMotorMoving = 1;
  74. if (*g_pAF_Opened >= 1)
  75. stMotorInfo.bIsMotorOpen = 1;
  76. else
  77. stMotorInfo.bIsMotorOpen = 0;
  78. if (copy_to_user(pstMotorInfo, &stMotorInfo, sizeof(stAF_MotorInfo)))
  79. LOG_INF("copy to user failed when getting motor information\n");
  80. return 0;
  81. }
  82. static void initdrv(void)
  83. {
  84. char puSendCmd2[2] = { 0x01, 0x39 };
  85. char puSendCmd3[2] = { 0x05, 0x65 };
  86. i2c_master_send(g_pstAF_I2Cclient, puSendCmd2, 2);
  87. i2c_master_send(g_pstAF_I2Cclient, puSendCmd3, 2);
  88. }
  89. static inline int moveAF(unsigned long a_u4Position)
  90. {
  91. int ret = 0;
  92. if ((a_u4Position > g_u4AF_MACRO) || (a_u4Position < g_u4AF_INF)) {
  93. LOG_INF("out of range\n");
  94. return -EINVAL;
  95. }
  96. if (*g_pAF_Opened == 1) {
  97. unsigned short InitPos;
  98. initdrv();
  99. ret = s4DW9718AF_ReadReg(&InitPos);
  100. if (ret == 0) {
  101. LOG_INF("Init Pos %6d\n", InitPos);
  102. spin_lock(g_pAF_SpinLock);
  103. g_u4CurrPosition = (unsigned long)InitPos;
  104. spin_unlock(g_pAF_SpinLock);
  105. } else {
  106. spin_lock(g_pAF_SpinLock);
  107. g_u4CurrPosition = 0;
  108. spin_unlock(g_pAF_SpinLock);
  109. }
  110. spin_lock(g_pAF_SpinLock);
  111. *g_pAF_Opened = 2;
  112. spin_unlock(g_pAF_SpinLock);
  113. }
  114. if (g_u4CurrPosition == a_u4Position)
  115. return 0;
  116. spin_lock(g_pAF_SpinLock);
  117. g_u4TargetPosition = a_u4Position;
  118. spin_unlock(g_pAF_SpinLock);
  119. /* LOG_INF("move [curr] %d [target] %d\n", g_u4CurrPosition, g_u4TargetPosition); */
  120. if (s4AF_WriteReg((unsigned short)g_u4TargetPosition) == 0) {
  121. spin_lock(g_pAF_SpinLock);
  122. g_u4CurrPosition = (unsigned long)g_u4TargetPosition;
  123. spin_unlock(g_pAF_SpinLock);
  124. } else {
  125. LOG_INF("set I2C failed when moving the motor\n");
  126. }
  127. return 0;
  128. }
  129. static inline int setAFInf(unsigned long a_u4Position)
  130. {
  131. spin_lock(g_pAF_SpinLock);
  132. g_u4AF_INF = a_u4Position;
  133. spin_unlock(g_pAF_SpinLock);
  134. return 0;
  135. }
  136. static inline int setAFMacro(unsigned long a_u4Position)
  137. {
  138. spin_lock(g_pAF_SpinLock);
  139. g_u4AF_MACRO = a_u4Position;
  140. spin_unlock(g_pAF_SpinLock);
  141. return 0;
  142. }
  143. /* ////////////////////////////////////////////////////////////// */
  144. long DW9718AF_Ioctl(struct file *a_pstFile, unsigned int a_u4Command, unsigned long a_u4Param)
  145. {
  146. long i4RetValue = 0;
  147. switch (a_u4Command) {
  148. case AFIOC_G_MOTORINFO:
  149. i4RetValue = getAFInfo((__user stAF_MotorInfo *) (a_u4Param));
  150. break;
  151. case AFIOC_T_MOVETO:
  152. i4RetValue = moveAF(a_u4Param);
  153. break;
  154. case AFIOC_T_SETINFPOS:
  155. i4RetValue = setAFInf(a_u4Param);
  156. break;
  157. case AFIOC_T_SETMACROPOS:
  158. i4RetValue = setAFMacro(a_u4Param);
  159. break;
  160. default:
  161. LOG_INF("No CMD\n");
  162. i4RetValue = -EPERM;
  163. break;
  164. }
  165. return i4RetValue;
  166. }
  167. /* Main jobs: */
  168. /* 1.Deallocate anything that "open" allocated in private_data. */
  169. /* 2.Shut down the device on last close. */
  170. /* 3.Only called once on last time. */
  171. /* Q1 : Try release multiple times. */
  172. int DW9718AF_Release(struct inode *a_pstInode, struct file *a_pstFile)
  173. {
  174. LOG_INF("Start\n");
  175. if (*g_pAF_Opened == 2)
  176. LOG_INF("Wait\n");
  177. if (*g_pAF_Opened) {
  178. LOG_INF("Free\n");
  179. spin_lock(g_pAF_SpinLock);
  180. *g_pAF_Opened = 0;
  181. spin_unlock(g_pAF_SpinLock);
  182. }
  183. LOG_INF("End\n");
  184. return 0;
  185. }
  186. void DW9718AF_SetI2Cclient(struct i2c_client *pstAF_I2Cclient, spinlock_t *pAF_SpinLock, int *pAF_Opened)
  187. {
  188. g_pstAF_I2Cclient = pstAF_I2Cclient;
  189. g_pAF_SpinLock = pAF_SpinLock;
  190. g_pAF_Opened = pAF_Opened;
  191. }