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