tuner_fc2580.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /*
  2. * FCI FC2580 tuner driver, taken from the kernel driver that can be found
  3. * on http://linux.terratec.de/tv_en.html
  4. *
  5. * This driver is a mess, and should be cleaned up/rewritten.
  6. *
  7. */
  8. #include <stdint.h>
  9. #include "rtlsdr_i2c.h"
  10. #include "tuner_fc2580.h"
  11. /* 16.384 MHz (at least on the Logilink VG0002A) */
  12. #define CRYSTAL_FREQ 16384000
  13. /* glue functions to rtl-sdr code */
  14. fc2580_fci_result_type fc2580_i2c_write(void *pTuner, unsigned char reg, unsigned char val)
  15. {
  16. uint8_t data[2];
  17. data[0] = reg;
  18. data[1] = val;
  19. if (rtlsdr_i2c_write_fn(pTuner, FC2580_I2C_ADDR, data, 2) < 0)
  20. return FC2580_FCI_FAIL;
  21. return FC2580_FCI_SUCCESS;
  22. }
  23. fc2580_fci_result_type fc2580_i2c_read(void *pTuner, unsigned char reg, unsigned char *read_data)
  24. {
  25. uint8_t data = reg;
  26. if (rtlsdr_i2c_write_fn(pTuner, FC2580_I2C_ADDR, &data, 1) < 0)
  27. return FC2580_FCI_FAIL;
  28. if (rtlsdr_i2c_read_fn(pTuner, FC2580_I2C_ADDR, &data, 1) < 0)
  29. return FC2580_FCI_FAIL;
  30. *read_data = data;
  31. return FC2580_FCI_SUCCESS;
  32. }
  33. int
  34. fc2580_Initialize(
  35. void *pTuner
  36. )
  37. {
  38. int AgcMode;
  39. unsigned int CrystalFreqKhz;
  40. //TODO set AGC mode
  41. AgcMode = FC2580_AGC_EXTERNAL;
  42. // Initialize tuner with AGC mode.
  43. // Note: CrystalFreqKhz = round(CrystalFreqHz / 1000)
  44. CrystalFreqKhz = (unsigned int)((CRYSTAL_FREQ + 500) / 1000);
  45. if(fc2580_set_init(pTuner, AgcMode, CrystalFreqKhz) != FC2580_FCI_SUCCESS)
  46. goto error_status_initialize_tuner;
  47. return FUNCTION_SUCCESS;
  48. error_status_initialize_tuner:
  49. return FUNCTION_ERROR;
  50. }
  51. int
  52. fc2580_SetRfFreqHz(
  53. void *pTuner,
  54. unsigned long RfFreqHz
  55. )
  56. {
  57. unsigned int RfFreqKhz;
  58. unsigned int CrystalFreqKhz;
  59. // Set tuner RF frequency in KHz.
  60. // Note: RfFreqKhz = round(RfFreqHz / 1000)
  61. // CrystalFreqKhz = round(CrystalFreqHz / 1000)
  62. RfFreqKhz = (unsigned int)((RfFreqHz + 500) / 1000);
  63. CrystalFreqKhz = (unsigned int)((CRYSTAL_FREQ + 500) / 1000);
  64. if(fc2580_set_freq(pTuner, RfFreqKhz, CrystalFreqKhz) != FC2580_FCI_SUCCESS)
  65. goto error_status_set_tuner_rf_frequency;
  66. return FUNCTION_SUCCESS;
  67. error_status_set_tuner_rf_frequency:
  68. return FUNCTION_ERROR;
  69. }
  70. /**
  71. @brief Set FC2580 tuner bandwidth mode.
  72. */
  73. int
  74. fc2580_SetBandwidthMode(
  75. void *pTuner,
  76. int BandwidthMode
  77. )
  78. {
  79. unsigned int CrystalFreqKhz;
  80. // Set tuner bandwidth mode.
  81. // Note: CrystalFreqKhz = round(CrystalFreqHz / 1000)
  82. CrystalFreqKhz = (unsigned int)((CRYSTAL_FREQ + 500) / 1000);
  83. if(fc2580_set_filter(pTuner, (unsigned char)BandwidthMode, CrystalFreqKhz) != FC2580_FCI_SUCCESS)
  84. goto error_status_set_tuner_bandwidth_mode;
  85. return FUNCTION_SUCCESS;
  86. error_status_set_tuner_bandwidth_mode:
  87. return FUNCTION_ERROR;
  88. }
  89. void fc2580_wait_msec(void *pTuner, int a)
  90. {
  91. /* USB latency is enough for now ;) */
  92. // usleep(a * 1000);
  93. return;
  94. }
  95. /*==============================================================================
  96. fc2580 initial setting
  97. This function is a generic function which gets called to initialize
  98. fc2580 in DVB-H mode or L-Band TDMB mode
  99. <input parameter>
  100. ifagc_mode
  101. type : integer
  102. 1 : Internal AGC
  103. 2 : Voltage Control Mode
  104. ==============================================================================*/
  105. fc2580_fci_result_type fc2580_set_init( void *pTuner, int ifagc_mode, unsigned int freq_xtal )
  106. {
  107. fc2580_fci_result_type result = FC2580_FCI_SUCCESS;
  108. result &= fc2580_i2c_write(pTuner, 0x00, 0x00); /*** Confidential ***/
  109. result &= fc2580_i2c_write(pTuner, 0x12, 0x86);
  110. result &= fc2580_i2c_write(pTuner, 0x14, 0x5C);
  111. result &= fc2580_i2c_write(pTuner, 0x16, 0x3C);
  112. result &= fc2580_i2c_write(pTuner, 0x1F, 0xD2);
  113. result &= fc2580_i2c_write(pTuner, 0x09, 0xD7);
  114. result &= fc2580_i2c_write(pTuner, 0x0B, 0xD5);
  115. result &= fc2580_i2c_write(pTuner, 0x0C, 0x32);
  116. result &= fc2580_i2c_write(pTuner, 0x0E, 0x43);
  117. result &= fc2580_i2c_write(pTuner, 0x21, 0x0A);
  118. result &= fc2580_i2c_write(pTuner, 0x22, 0x82);
  119. if( ifagc_mode == 1 )
  120. {
  121. result &= fc2580_i2c_write(pTuner, 0x45, 0x10); //internal AGC
  122. result &= fc2580_i2c_write(pTuner, 0x4C, 0x00); //HOLD_AGC polarity
  123. }
  124. else if( ifagc_mode == 2 )
  125. {
  126. result &= fc2580_i2c_write(pTuner, 0x45, 0x20); //Voltage Control Mode
  127. result &= fc2580_i2c_write(pTuner, 0x4C, 0x02); //HOLD_AGC polarity
  128. }
  129. result &= fc2580_i2c_write(pTuner, 0x3F, 0x88);
  130. result &= fc2580_i2c_write(pTuner, 0x02, 0x0E);
  131. result &= fc2580_i2c_write(pTuner, 0x58, 0x14);
  132. result &= fc2580_set_filter(pTuner, 8, freq_xtal); //BW = 7.8MHz
  133. return result;
  134. }
  135. /*==============================================================================
  136. fc2580 frequency setting
  137. This function is a generic function which gets called to change LO Frequency
  138. of fc2580 in DVB-H mode or L-Band TDMB mode
  139. <input parameter>
  140. freq_xtal: kHz
  141. f_lo
  142. Value of target LO Frequency in 'kHz' unit
  143. ex) 2.6GHz = 2600000
  144. ==============================================================================*/
  145. fc2580_fci_result_type fc2580_set_freq( void *pTuner, unsigned int f_lo, unsigned int freq_xtal )
  146. {
  147. unsigned int f_diff, f_diff_shifted, n_val, k_val;
  148. unsigned int f_vco, r_val, f_comp;
  149. unsigned char pre_shift_bits = 4;// number of preshift to prevent overflow in shifting f_diff to f_diff_shifted
  150. unsigned char data_0x18;
  151. unsigned char data_0x02 = (USE_EXT_CLK<<5)|0x0E;
  152. fc2580_band_type band = ( f_lo > 1000000 )? FC2580_L_BAND : ( f_lo > 400000 )? FC2580_UHF_BAND : FC2580_VHF_BAND;
  153. fc2580_fci_result_type result = FC2580_FCI_SUCCESS;
  154. f_vco = ( band == FC2580_UHF_BAND )? f_lo * 4 : (( band == FC2580_L_BAND )? f_lo * 2 : f_lo * 12);
  155. r_val = ( f_vco >= 2*76*freq_xtal )? 1 : ( f_vco >= 76*freq_xtal )? 2 : 4;
  156. f_comp = freq_xtal/r_val;
  157. n_val = ( f_vco / 2 ) / f_comp;
  158. f_diff = f_vco - 2* f_comp * n_val;
  159. f_diff_shifted = f_diff << ( 20 - pre_shift_bits );
  160. k_val = f_diff_shifted / ( ( 2* f_comp ) >> pre_shift_bits );
  161. if( f_diff_shifted - k_val * ( ( 2* f_comp ) >> pre_shift_bits ) >= ( f_comp >> pre_shift_bits ) )
  162. k_val = k_val + 1;
  163. if( f_vco >= BORDER_FREQ ) //Select VCO Band
  164. data_0x02 = data_0x02 | 0x08; //0x02[3] = 1;
  165. else
  166. data_0x02 = data_0x02 & 0xF7; //0x02[3] = 0;
  167. // if( band != curr_band ) {
  168. switch(band)
  169. {
  170. case FC2580_UHF_BAND:
  171. data_0x02 = (data_0x02 & 0x3F);
  172. result &= fc2580_i2c_write(pTuner, 0x25, 0xF0);
  173. result &= fc2580_i2c_write(pTuner, 0x27, 0x77);
  174. result &= fc2580_i2c_write(pTuner, 0x28, 0x53);
  175. result &= fc2580_i2c_write(pTuner, 0x29, 0x60);
  176. result &= fc2580_i2c_write(pTuner, 0x30, 0x09);
  177. result &= fc2580_i2c_write(pTuner, 0x50, 0x8C);
  178. result &= fc2580_i2c_write(pTuner, 0x53, 0x50);
  179. if( f_lo < 538000 )
  180. result &= fc2580_i2c_write(pTuner, 0x5F, 0x13);
  181. else
  182. result &= fc2580_i2c_write(pTuner, 0x5F, 0x15);
  183. if( f_lo < 538000 )
  184. {
  185. result &= fc2580_i2c_write(pTuner, 0x61, 0x07);
  186. result &= fc2580_i2c_write(pTuner, 0x62, 0x06);
  187. result &= fc2580_i2c_write(pTuner, 0x67, 0x06);
  188. result &= fc2580_i2c_write(pTuner, 0x68, 0x08);
  189. result &= fc2580_i2c_write(pTuner, 0x69, 0x10);
  190. result &= fc2580_i2c_write(pTuner, 0x6A, 0x12);
  191. }
  192. else if( f_lo < 794000 )
  193. {
  194. result &= fc2580_i2c_write(pTuner, 0x61, 0x03);
  195. result &= fc2580_i2c_write(pTuner, 0x62, 0x03);
  196. result &= fc2580_i2c_write(pTuner, 0x67, 0x03); //ACI improve
  197. result &= fc2580_i2c_write(pTuner, 0x68, 0x05); //ACI improve
  198. result &= fc2580_i2c_write(pTuner, 0x69, 0x0C);
  199. result &= fc2580_i2c_write(pTuner, 0x6A, 0x0E);
  200. }
  201. else
  202. {
  203. result &= fc2580_i2c_write(pTuner, 0x61, 0x07);
  204. result &= fc2580_i2c_write(pTuner, 0x62, 0x06);
  205. result &= fc2580_i2c_write(pTuner, 0x67, 0x07);
  206. result &= fc2580_i2c_write(pTuner, 0x68, 0x09);
  207. result &= fc2580_i2c_write(pTuner, 0x69, 0x10);
  208. result &= fc2580_i2c_write(pTuner, 0x6A, 0x12);
  209. }
  210. result &= fc2580_i2c_write(pTuner, 0x63, 0x15);
  211. result &= fc2580_i2c_write(pTuner, 0x6B, 0x0B);
  212. result &= fc2580_i2c_write(pTuner, 0x6C, 0x0C);
  213. result &= fc2580_i2c_write(pTuner, 0x6D, 0x78);
  214. result &= fc2580_i2c_write(pTuner, 0x6E, 0x32);
  215. result &= fc2580_i2c_write(pTuner, 0x6F, 0x14);
  216. result &= fc2580_set_filter(pTuner, 8, freq_xtal); //BW = 7.8MHz
  217. break;
  218. case FC2580_VHF_BAND:
  219. data_0x02 = (data_0x02 & 0x3F) | 0x80;
  220. result &= fc2580_i2c_write(pTuner, 0x27, 0x77);
  221. result &= fc2580_i2c_write(pTuner, 0x28, 0x33);
  222. result &= fc2580_i2c_write(pTuner, 0x29, 0x40);
  223. result &= fc2580_i2c_write(pTuner, 0x30, 0x09);
  224. result &= fc2580_i2c_write(pTuner, 0x50, 0x8C);
  225. result &= fc2580_i2c_write(pTuner, 0x53, 0x50);
  226. result &= fc2580_i2c_write(pTuner, 0x5F, 0x0F);
  227. result &= fc2580_i2c_write(pTuner, 0x61, 0x07);
  228. result &= fc2580_i2c_write(pTuner, 0x62, 0x00);
  229. result &= fc2580_i2c_write(pTuner, 0x63, 0x15);
  230. result &= fc2580_i2c_write(pTuner, 0x67, 0x03);
  231. result &= fc2580_i2c_write(pTuner, 0x68, 0x05);
  232. result &= fc2580_i2c_write(pTuner, 0x69, 0x10);
  233. result &= fc2580_i2c_write(pTuner, 0x6A, 0x12);
  234. result &= fc2580_i2c_write(pTuner, 0x6B, 0x08);
  235. result &= fc2580_i2c_write(pTuner, 0x6C, 0x0A);
  236. result &= fc2580_i2c_write(pTuner, 0x6D, 0x78);
  237. result &= fc2580_i2c_write(pTuner, 0x6E, 0x32);
  238. result &= fc2580_i2c_write(pTuner, 0x6F, 0x54);
  239. result &= fc2580_set_filter(pTuner, 7, freq_xtal); //BW = 6.8MHz
  240. break;
  241. case FC2580_L_BAND:
  242. data_0x02 = (data_0x02 & 0x3F) | 0x40;
  243. result &= fc2580_i2c_write(pTuner, 0x2B, 0x70);
  244. result &= fc2580_i2c_write(pTuner, 0x2C, 0x37);
  245. result &= fc2580_i2c_write(pTuner, 0x2D, 0xE7);
  246. result &= fc2580_i2c_write(pTuner, 0x30, 0x09);
  247. result &= fc2580_i2c_write(pTuner, 0x44, 0x20);
  248. result &= fc2580_i2c_write(pTuner, 0x50, 0x8C);
  249. result &= fc2580_i2c_write(pTuner, 0x53, 0x50);
  250. result &= fc2580_i2c_write(pTuner, 0x5F, 0x0F);
  251. result &= fc2580_i2c_write(pTuner, 0x61, 0x0F);
  252. result &= fc2580_i2c_write(pTuner, 0x62, 0x00);
  253. result &= fc2580_i2c_write(pTuner, 0x63, 0x13);
  254. result &= fc2580_i2c_write(pTuner, 0x67, 0x00);
  255. result &= fc2580_i2c_write(pTuner, 0x68, 0x02);
  256. result &= fc2580_i2c_write(pTuner, 0x69, 0x0C);
  257. result &= fc2580_i2c_write(pTuner, 0x6A, 0x0E);
  258. result &= fc2580_i2c_write(pTuner, 0x6B, 0x08);
  259. result &= fc2580_i2c_write(pTuner, 0x6C, 0x0A);
  260. result &= fc2580_i2c_write(pTuner, 0x6D, 0xA0);
  261. result &= fc2580_i2c_write(pTuner, 0x6E, 0x50);
  262. result &= fc2580_i2c_write(pTuner, 0x6F, 0x14);
  263. result &= fc2580_set_filter(pTuner, 1, freq_xtal); //BW = 1.53MHz
  264. break;
  265. default:
  266. break;
  267. }
  268. // curr_band = band;
  269. // }
  270. //A command about AGC clock's pre-divide ratio
  271. if( freq_xtal >= 28000 )
  272. result &= fc2580_i2c_write(pTuner, 0x4B, 0x22 );
  273. //Commands about VCO Band and PLL setting.
  274. result &= fc2580_i2c_write(pTuner, 0x02, data_0x02);
  275. data_0x18 = ( ( r_val == 1 )? 0x00 : ( ( r_val == 2 )? 0x10 : 0x20 ) ) + (unsigned char)(k_val >> 16);
  276. result &= fc2580_i2c_write(pTuner, 0x18, data_0x18); //Load 'R' value and high part of 'K' values
  277. result &= fc2580_i2c_write(pTuner, 0x1A, (unsigned char)( k_val >> 8 ) ); //Load middle part of 'K' value
  278. result &= fc2580_i2c_write(pTuner, 0x1B, (unsigned char)( k_val ) ); //Load lower part of 'K' value
  279. result &= fc2580_i2c_write(pTuner, 0x1C, (unsigned char)( n_val ) ); //Load 'N' value
  280. //A command about UHF LNA Load Cap
  281. if( band == FC2580_UHF_BAND )
  282. result &= fc2580_i2c_write(pTuner, 0x2D, ( f_lo <= (unsigned int)794000 )? 0x9F : 0x8F ); //LNA_OUT_CAP
  283. return result;
  284. }
  285. /*==============================================================================
  286. fc2580 filter BW setting
  287. This function is a generic function which gets called to change Bandwidth
  288. frequency of fc2580's channel selection filter
  289. <input parameter>
  290. freq_xtal: kHz
  291. filter_bw
  292. 1 : 1.53MHz(TDMB)
  293. 6 : 6MHz (Bandwidth 6MHz)
  294. 7 : 6.8MHz (Bandwidth 7MHz)
  295. 8 : 7.8MHz (Bandwidth 8MHz)
  296. ==============================================================================*/
  297. fc2580_fci_result_type fc2580_set_filter( void *pTuner, unsigned char filter_bw, unsigned int freq_xtal )
  298. {
  299. unsigned char cal_mon = 0, i;
  300. fc2580_fci_result_type result = FC2580_FCI_SUCCESS;
  301. if(filter_bw == 1)
  302. {
  303. result &= fc2580_i2c_write(pTuner, 0x36, 0x1C);
  304. result &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(4151*freq_xtal/1000000) );
  305. result &= fc2580_i2c_write(pTuner, 0x39, 0x00);
  306. result &= fc2580_i2c_write(pTuner, 0x2E, 0x09);
  307. }
  308. if(filter_bw == 6)
  309. {
  310. result &= fc2580_i2c_write(pTuner, 0x36, 0x18);
  311. result &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(4400*freq_xtal/1000000) );
  312. result &= fc2580_i2c_write(pTuner, 0x39, 0x00);
  313. result &= fc2580_i2c_write(pTuner, 0x2E, 0x09);
  314. }
  315. else if(filter_bw == 7)
  316. {
  317. result &= fc2580_i2c_write(pTuner, 0x36, 0x18);
  318. result &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(3910*freq_xtal/1000000) );
  319. result &= fc2580_i2c_write(pTuner, 0x39, 0x80);
  320. result &= fc2580_i2c_write(pTuner, 0x2E, 0x09);
  321. }
  322. else if(filter_bw == 8)
  323. {
  324. result &= fc2580_i2c_write(pTuner, 0x36, 0x18);
  325. result &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(3300*freq_xtal/1000000) );
  326. result &= fc2580_i2c_write(pTuner, 0x39, 0x80);
  327. result &= fc2580_i2c_write(pTuner, 0x2E, 0x09);
  328. }
  329. for(i=0; i<5; i++)
  330. {
  331. fc2580_wait_msec(pTuner, 5);//wait 5ms
  332. result &= fc2580_i2c_read(pTuner, 0x2F, &cal_mon);
  333. if( (cal_mon & 0xC0) != 0xC0)
  334. {
  335. result &= fc2580_i2c_write(pTuner, 0x2E, 0x01);
  336. result &= fc2580_i2c_write(pTuner, 0x2E, 0x09);
  337. }
  338. else
  339. break;
  340. }
  341. result &= fc2580_i2c_write(pTuner, 0x2E, 0x01);
  342. return result;
  343. }
  344. /*==============================================================================
  345. fc2580 RSSI function
  346. This function is a generic function which returns fc2580's
  347. current RSSI value.
  348. <input parameter>
  349. none
  350. <return value>
  351. int
  352. rssi : estimated input power.
  353. ==============================================================================*/
  354. //int fc2580_get_rssi(void) {
  355. //
  356. // unsigned char s_lna, s_rfvga, s_cfs, s_ifvga;
  357. // int ofs_lna, ofs_rfvga, ofs_csf, ofs_ifvga, rssi;
  358. //
  359. // fc2580_i2c_read(0x71, &s_lna );
  360. // fc2580_i2c_read(0x72, &s_rfvga );
  361. // fc2580_i2c_read(0x73, &s_cfs );
  362. // fc2580_i2c_read(0x74, &s_ifvga );
  363. //
  364. //
  365. // ofs_lna =
  366. // (curr_band==FC2580_UHF_BAND)?
  367. // (s_lna==0)? 0 :
  368. // (s_lna==1)? -6 :
  369. // (s_lna==2)? -17 :
  370. // (s_lna==3)? -22 : -30 :
  371. // (curr_band==FC2580_VHF_BAND)?
  372. // (s_lna==0)? 0 :
  373. // (s_lna==1)? -6 :
  374. // (s_lna==2)? -19 :
  375. // (s_lna==3)? -24 : -32 :
  376. // (curr_band==FC2580_L_BAND)?
  377. // (s_lna==0)? 0 :
  378. // (s_lna==1)? -6 :
  379. // (s_lna==2)? -11 :
  380. // (s_lna==3)? -16 : -34 :
  381. // 0;//FC2580_NO_BAND
  382. // ofs_rfvga = -s_rfvga+((s_rfvga>=11)? 1 : 0) + ((s_rfvga>=18)? 1 : 0);
  383. // ofs_csf = -6*s_cfs;
  384. // ofs_ifvga = s_ifvga/4;
  385. //
  386. // return rssi = ofs_lna+ofs_rfvga+ofs_csf+ofs_ifvga+OFS_RSSI;
  387. //
  388. //}
  389. /*==============================================================================
  390. fc2580 Xtal frequency Setting
  391. This function is a generic function which sets
  392. the frequency of xtal.
  393. <input parameter>
  394. frequency
  395. frequency value of internal(external) Xtal(clock) in kHz unit.
  396. ==============================================================================*/
  397. //void fc2580_set_freq_xtal(unsigned int frequency) {
  398. //
  399. // freq_xtal = frequency;
  400. //
  401. //}