tuner_drv_hw.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. *
  3. * drivers/media/isdbtmm/tuner_drv_hw.c
  4. *
  5. * MM Tuner Driver
  6. *
  7. * Copyright (C) (2013, Samsung Electronics)
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation version 2.
  12. *
  13. * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  14. * kind, whether express or implied; without even the implied warranty
  15. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. */
  19. /******************************************************************************/
  20. /* include */
  21. /******************************************************************************/
  22. #include <linux/module.h>
  23. #include <linux/kernel.h>
  24. #include <linux/init.h>
  25. #include <linux/types.h>
  26. #include <linux/fs.h>
  27. #include <linux/cdev.h>
  28. #include <linux/sched.h>
  29. #include <linux/platform_device.h>
  30. #include <linux/device.h>
  31. #include <linux/err.h>
  32. #include <linux/slab.h>
  33. #include <linux/i2c.h>
  34. #include <linux/i2c-dev.h>
  35. #include <asm/uaccess.h>
  36. #include "tuner_drv.h"
  37. #include <linux/mm.h>
  38. #include <linux/vmalloc.h>
  39. /* #define USER_DEBUG_LOG */
  40. /******************************************************************************
  41. * function
  42. ******************************************************************************/
  43. int tuner_drv_hw_access( unsigned int uCommand, TUNER_DATA_RW *data,
  44. unsigned short param_len );
  45. /******************************************************************************
  46. * code area
  47. ******************************************************************************/
  48. /******************************************************************************
  49. * function: tuner_drv_hw_access
  50. * brief : HW access control of a driver
  51. * repeat specified count single register access
  52. * date : 2011.08.02
  53. * author : K.Kitamura(*)
  54. * modifier: K.Okawa(KXD14)
  55. *
  56. * return : 0 normal exit
  57. * : -1 error exit
  58. * input : uCommand setting command
  59. * : data access data
  60. * : param_len nummber of access data
  61. * output : none
  62. ******************************************************************************/
  63. int tuner_drv_hw_access( unsigned int uCommand, TUNER_DATA_RW *data,
  64. unsigned short param_len )
  65. {
  66. int ret;
  67. struct i2c_adapter *adap = NULL;
  68. struct i2c_msg msgs[2];
  69. unsigned short addr;
  70. unsigned short flags;
  71. unsigned char buf[TUNER_I2C_MSG_DATA_NUM];
  72. unsigned char read_data;
  73. unsigned char ena_data;
  74. unsigned char write_data;
  75. unsigned short loop_cnt;
  76. /* argument check */
  77. if( data == NULL )
  78. {
  79. TRACE();
  80. return -EINVAL;
  81. }
  82. /* get i2c adapter */
  83. adap = i2c_get_adapter( TUNER_CONFIG_I2C_BUSNUM );
  84. if( adap == NULL )
  85. {
  86. TRACE();
  87. return -EINVAL;
  88. }
  89. /* initialize */
  90. memset( msgs, 0x00, sizeof(struct i2c_msg) * 2 );
  91. ena_data = 0x00;
  92. flags = 0;
  93. /* access loop */
  94. for( loop_cnt = 0; loop_cnt < param_len; loop_cnt++ ) {
  95. /* initialize i2c messages */
  96. memset( msgs, 0x00, sizeof(struct i2c_msg) * 2 );
  97. ena_data = 0x00;
  98. /* command detect switch */
  99. switch ( uCommand ) {
  100. case TUNER_IOCTL_VALGET: /* read access */
  101. addr = data[ loop_cnt ].slave_adr;
  102. flags = I2C_M_RD;
  103. buf[ 0 ] = (unsigned char)data[ loop_cnt ].adr;
  104. buf[ 1 ] = 0;
  105. break;
  106. case TUNER_IOCTL_VALSET: /* write access */
  107. addr = data[ loop_cnt ].slave_adr;
  108. flags = 0;
  109. buf[ 0 ] = (unsigned char)data[ loop_cnt ].adr;
  110. buf[ 1 ] = (unsigned char)data[ loop_cnt ].param;
  111. break;
  112. default:
  113. i2c_put_adapter( adap );
  114. return -EINVAL;
  115. }
  116. if( flags != I2C_M_RD ) {
  117. /* bit modify write */
  118. if( !(( data[ loop_cnt ].sbit == 0 ) &&
  119. ( data[ loop_cnt ].ebit == 7 )))
  120. {
  121. /* specified start/end bit position mode */
  122. /* TODO: enabit */
  123. if(( data[ loop_cnt ].sbit == TUNER_SET_ENADATA )
  124. && ( data[ loop_cnt ].ebit == TUNER_SET_ENADATA ))
  125. {
  126. ena_data = ( unsigned char )data[ loop_cnt ].enabit;
  127. }
  128. else
  129. {
  130. /* calculate enable bit mask */
  131. ena_data = (unsigned char)(((1U <<
  132. (1+data[loop_cnt].ebit-data[loop_cnt].sbit))-1) <<
  133. data[loop_cnt].sbit);
  134. }
  135. if( ena_data != 0xFF )
  136. {
  137. /* read a current value */
  138. msgs[ 0 ].addr = addr;
  139. msgs[ 0 ].flags = 0;
  140. msgs[ 0 ].len = TUNER_R_MSGLEN;
  141. msgs[ 0 ].buf = &buf[ 0 ];
  142. msgs[ 1 ].addr = addr;
  143. msgs[ 1 ].flags = I2C_M_RD;
  144. msgs[ 1 ].len = TUNER_R_MSGLEN;
  145. msgs[ 1 ].buf = &read_data;
  146. ret = i2c_transfer( adap, msgs, TUNER_R_MSGNUM );
  147. if( ret < 0 )
  148. {
  149. TRACE();
  150. i2c_put_adapter( adap );
  151. return -EINVAL;
  152. }
  153. /* initialize i2c message */
  154. memset( msgs, 0x00, sizeof( struct i2c_msg ) * 2 );
  155. /* clear bits of write position */
  156. read_data &= ( unsigned char )( ~ena_data );
  157. /* construct a write value */
  158. write_data = ( unsigned char )( ena_data &
  159. data[ loop_cnt ].param );
  160. buf[ 1 ] = ( unsigned char )( write_data | read_data );
  161. }
  162. }
  163. #ifdef USER_DEBUG_LOG
  164. DEBUG_PRINT(
  165. "ioctl(W) slv:0x%02x adr:0x%02x 0x%02x (RMW:0x%02x WDAT:0x%02x)",
  166. addr, buf[ 0 ], data[ loop_cnt ].param, read_data, buf[ 1 ]);
  167. #endif /* USER_DEBUG_LOG */
  168. msgs[ 0 ].addr = addr;
  169. msgs[ 0 ].flags = flags;
  170. msgs[ 0 ].len = TUNER_W_MSGLEN;
  171. msgs[ 0 ].buf = buf;
  172. ret = i2c_transfer( adap, msgs, TUNER_W_MSGNUM );
  173. if( ret < 0 )
  174. {
  175. TRACE();
  176. i2c_put_adapter( adap );
  177. return -EINVAL;
  178. }
  179. } else {
  180. /* write register */
  181. msgs[ 0 ].addr = addr;
  182. msgs[ 0 ].flags = 0;
  183. msgs[ 0 ].len = TUNER_R_MSGLEN;
  184. msgs[ 0 ].buf = &buf[ 0 ];
  185. msgs[ 1 ].addr = addr;
  186. msgs[ 1 ].flags = flags;
  187. msgs[ 1 ].len = TUNER_R_MSGLEN;
  188. msgs[ 1 ].buf = &buf[ 1 ];
  189. #ifdef USER_DEBUG_LOG
  190. DEBUG_PRINT("ioctl(read(Pre)) slv:0x%02x adr:0x%02x (single)",
  191. addr, buf[ 0 ]);
  192. #endif /* USER_DEBUG_LOG */
  193. ret = i2c_transfer( adap, msgs, TUNER_R_MSGNUM );
  194. if( ret < 0 )
  195. {
  196. TRACE();
  197. i2c_put_adapter( adap );
  198. return -EINVAL;
  199. }
  200. /* return read val. */
  201. data[ loop_cnt ].param = buf[ 1 ];
  202. #ifdef USER_DEBUG_LOG
  203. DEBUG_PRINT(
  204. "ioctl(R) slv:0x%02x adr:0x%02x 0x%02x (RETURN:0x%02x)",
  205. addr, buf[ 0 ], buf[1], data[ loop_cnt ].param);
  206. #endif /* USER_DEBUG_LOG */
  207. }
  208. }
  209. i2c_put_adapter( adap );
  210. return 0;
  211. }