MT6620: add the new driver JB2 V1.0
[firefly-linux-kernel-4.4.55.git] / drivers / mtk_wcn_combo / drv_fm / mt6620 / pub / mt6620_fm_lib.c
1 #include <linux/semaphore.h>
2 #include <linux/delay.h>
3 #include <linux/slab.h>
4
5 #include "stp_exp.h"
6 #include "wmt_exp.h"
7
8 #include "fm_typedef.h"
9 #include "fm_dbg.h"
10 #include "fm_err.h"
11 #include "fm_interface.h"
12 #include "fm_stdlib.h"
13 #include "fm_utils.h"
14 #include "fm_patch.h"
15 #include "fm_link.h"
16 #include "fm_config.h"
17 #include "fm_private.h"
18
19 #include "mt6620_fm_reg.h"
20 #include "mt6620_fm.h"
21 //#include "mt6620_drv_dsp.h"
22 //#include "mt6620_fm_link.h"
23 #include "mt6620_fm_lib.h"
24 #include "mt6620_fm_cmd.h"
25 #include "mt6620_fm_cust_cfg.h"
26 #ifdef MTK_FM_50KHZ_SUPPORT
27 static struct fm_fifo *cqi_fifo = NULL;
28 #endif
29 extern fm_cust_cfg mt6620_fm_config;
30 static struct fm_hw_info mt6620_hw_info = {
31     .chip_id = 0x00006620,
32     .eco_ver = 0x00000000,
33     .rom_ver = 0x00000002,
34     .patch_ver = 0x00000111,
35     .reserve = 0x00000000,
36 };
37 static struct fm_i2s_info mt6620_i2s_inf = {
38     .status = 0,    //i2s off
39     .mode = 0,      //slave mode
40     .rate = 48000,  //48000 sample rate
41 };
42
43 fm_s32 MT6620_HL_Side_Adj(fm_u16 freq, fm_s32 *hl);
44 fm_s32 MT6620_ADPLL_Freq_Avoid(fm_u16 freq, fm_s32 *freqavoid);
45 fm_s32 MT6620_MCU_Freq_Avoid(fm_u16 freq, fm_s32 *freqavoid);
46 fm_s32 MT6620_ADPLL_Power_OnOff(fm_s32 onoff, fm_s32 ADPLL_clk);
47 fm_s32 MT6620_TX_PWR_CTRL(fm_u16 freq, fm_s32 *ctr);
48 fm_s32 MT6620_RTC_Drift_CTRL(fm_u16 freq, fm_s32 *ctr);
49 fm_s32 MT6620_TX_DESENSE(fm_u16 freq, fm_s32 *ctr);
50
51 static fm_s32 mt6620_I2s_Setting(fm_s32 onoff, fm_s32 mode, fm_s32 sample);
52 static fm_s32 mt6620_desense_check(fm_u16 freq,fm_s32 rssi);
53 static fm_s32 MT6620_Rds_Tx(fm_u16 pi, fm_u16 *ps, fm_u16 *other_rds, fm_u8 other_rds_cnt);
54 static fm_s32 MT6620_Rds_Tx_Enable(void);
55 static fm_s32 MT6620_Rds_Tx_Disable(void);
56
57 static fm_u8 *cmd_buf = NULL;
58 static struct fm_lock *cmd_buf_lock = NULL;
59 static struct fm_callback *fm_cb_op;
60 //static struct MT6620fm_priv priv_adv_6620;
61 static ENUM_WMTHWVER_TYPE_T hw_ver=WMTHWVER_MT6620_E3;
62 static fm_s32 mt6620_pwron(fm_s32 data)
63 {
64     if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM)) {
65         WCN_DBG(FM_ALT | CHIP, "WMT turn on FM Fail!\n");
66         return -FM_ELINK;
67     } else {
68                  /* GeorgeKuo: turn on function before check stp ready */
69                 if(fm_false == mtk_wcn_stp_is_ready())
70                 {
71                         WCN_DBG(FM_ALT | MAIN,"6620 stp is not ready, please retry later\n");
72                         return -FM_ELINK;
73                 }
74                 hw_ver = mtk_wcn_wmt_hwver_get();
75         WCN_DBG(FM_ALT | CHIP, "WMT turn on FM OK!\n");
76         return 0;
77     }
78 }
79
80
81 static fm_s32 mt6620_pwroff(fm_s32 data)
82 {
83     if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_FM)) {
84         WCN_DBG(FM_ALT | CHIP, "WMT turn off FM Fail!\n");
85         return -FM_ELINK;
86     } else {
87         WCN_DBG(FM_NTC | CHIP, "WMT turn off FM OK!\n");
88         return 0;
89     }
90 }
91
92 static fm_s32 Delayms(fm_u32 data)
93 {
94     WCN_DBG(FM_DBG | CHIP, "delay %dms\n", data);
95     msleep(data);
96     return 0;
97 }
98
99 static fm_s32 Delayus(fm_u32 data)
100 {
101     WCN_DBG(FM_DBG | CHIP, "delay %dus\n", data);
102     udelay(data);
103     return 0;
104 }
105
106 static struct fm_res_ctx *res = NULL;
107
108 fm_s32 mt6620_get_read_result(struct fm_res_ctx* result)
109 {
110     FMR_ASSERT(result);
111     res = result;
112
113     return 0;
114 }
115
116 static fm_s32 mt6620_read(fm_u8 addr, fm_u16 *val)
117 {
118     fm_s32 ret = 0;
119     fm_u16 pkt_size;
120
121     if (FM_LOCK(cmd_buf_lock)) 
122                 return (-FM_ELOCK);
123     pkt_size = mt6620_get_reg(cmd_buf, TX_BUF_SIZE, addr);
124     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_FSPI_RD, SW_RETRY_CNT, FSPI_RD_TIMEOUT, mt6620_get_read_result);
125
126     if (!ret && res) {
127         *val = res->fspi_rd;
128     }
129
130     FM_UNLOCK(cmd_buf_lock);
131
132     return ret;
133 }
134
135 static fm_s32 mt6620_write(fm_u8 addr, fm_u16 val)
136 {
137     fm_s32 ret = 0;
138     fm_u16 pkt_size;
139
140     if (FM_LOCK(cmd_buf_lock)) 
141                 return (-FM_ELOCK);
142     pkt_size = mt6620_set_reg(cmd_buf, TX_BUF_SIZE, addr, val);
143     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_FSPI_WR, SW_RETRY_CNT, FSPI_WR_TIMEOUT, NULL);
144     FM_UNLOCK(cmd_buf_lock);
145
146     return ret;
147 }
148
149 static fm_s32 mt6620_set_bits(fm_u8 addr, fm_u16 bits, fm_u16 mask)
150 {
151     fm_s32 ret = 0;
152     fm_u16 val;
153
154     ret = mt6620_read(addr, &val);
155
156     if (ret)
157         return ret;
158
159     val = ((val & (mask)) | bits);
160     ret = mt6620_write(addr, val);
161
162     return ret;
163 }
164
165 static fm_u16 mt6620_get_chipid(void)
166 {
167     return 0x6620;
168 }
169
170 /*  mt6620_SetAntennaType - set Antenna type
171  *  @type - 1,Short Antenna;  0, Long Antenna
172  */
173 static fm_s32 mt6620_SetAntennaType(fm_s32 type)
174 {
175     WCN_DBG(FM_DBG | CHIP, "set ana to %s\n", type ? "short" : "long");
176
177     if (type == FM_ANA_LONG) {
178         //Long Antenna RSSI threshold, 0xE0 D0~D9
179         mt6620_write(0xE0, ((0xA301 & 0xFC00) | (FMR_RSSI_TH_LONG_MT6620 & 0x03FF)));
180         //Turn on Short Antenna LNA and Off TR Switch
181         mt6620_write(0x04, 0x0142);
182         //Turn off the Short Antenna Capbank biasing
183         mt6620_write(0x05, 0x00E7);
184         //Turn off the Short Antenna Capbank biasing
185         mt6620_write(0x26, 0x0004);
186         //Disable concurrent calibration for VCO and SCAL
187         mt6620_write(0x2E, 0x0008);
188     } else if (type == FM_ANA_SHORT) {
189         //Short Antenna RSSI threshold, 0xE0 D0~D9
190         mt6620_write(0xE0, ((0xA2E0 & 0xFC00) | (FMR_RSSI_TH_SHORT_MT6620 & 0x03FF)));
191         //Turn on Short Antenna LNA and TR Switch
192         mt6620_write(0x04, 0x0145);
193         //Turn on the Short Antenna Capbank biasing
194         mt6620_write(0x05, 0x00FF);
195         //Turn on the Short Antenna Capbank biasing
196         mt6620_write(0x26, 0x0024);
197         //Enable concurrent calibration for VCO and SCAL
198         mt6620_write(0x2E, 0x0000);
199     } else {
200         WCN_DBG(FM_ERR | CHIP, "%s()\n", __func__);
201         return -FM_EPARA;
202     }
203
204     return 0;
205 }
206
207 static fm_s32 mt6620_GetAntennaType(void)
208 {
209     fm_u16 dataRead;
210
211     mt6620_read(0x2E, &dataRead);
212
213     if (dataRead == 0x0000)
214         return FM_ANA_SHORT; //short antenna
215     else
216         return FM_ANA_LONG; //long antenna
217 }
218
219 static fm_s32 mt6620_Mute(fm_bool mute)
220 {
221     WCN_DBG(FM_DBG | CHIP, "set %s\n", mute ? "mute" : "unmute");
222
223     if (mute) {
224         return mt6620_set_bits(0x9C, 0x0008, 0xFFF7); //1:9C D3 = 1
225     } else {
226         return mt6620_set_bits(0x9c, 0x0000, 0xFFF7); //1:9C D3 = 0
227     }
228 }
229
230 static fm_s32 mt6620_RampDown(void)
231 {
232     fm_s32 ret = 0;
233     fm_u16 pkt_size;
234
235     WCN_DBG(FM_NTC | CHIP, "ramp down\n");
236
237     if (FM_LOCK(cmd_buf_lock)) 
238                 return (-FM_ELOCK);
239     pkt_size = mt6620_rampdown(cmd_buf, TX_BUF_SIZE);
240     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_RAMPDOWN, SW_RETRY_CNT, RAMPDOWN_TIMEOUT, NULL);
241     FM_UNLOCK(cmd_buf_lock);
242
243     if (ret) {
244         WCN_DBG(FM_ERR | CHIP, "ramp down failed\n");
245     }
246
247     return ret;
248 }
249 #if 0//ramp down tx will do in tx tune  flow
250 static fm_s32 MT6620_RampDown_Tx(void)
251 {
252     fm_s32 ret = 0;
253     fm_u16 pkt_size = 0;
254
255     WCN_DBG(FM_NTC | CHIP, "ramp down TX\n");
256     if (FM_LOCK(cmd_buf_lock)) 
257                 return (-FM_ELOCK);
258     
259     pkt_size = mt6620_rampdown_tx(cmd_buf, TX_BUF_SIZE);
260     ret = fm_cmd_tx(cmd_buf, pkt_size,FLAG_RAMPDOWN, SW_RETRY_CNT, RAMPDOWN_TIMEOUT,NULL);
261     
262     FM_UNLOCK(cmd_buf_lock);
263     if (ret) {
264         WCN_DBG(FM_ERR | CHIP, "ramp down TX failed\n");
265     }
266     return ret;
267 }
268 #endif
269 static fm_s32 mt6620_PowerUp(fm_u16 *chip_id, fm_u16 *device_id)
270 {
271     fm_s32 ret = 0;
272     fm_u16 pkt_size;
273
274     FMR_ASSERT(chip_id);
275     FMR_ASSERT(device_id);
276
277     WCN_DBG(FM_DBG | CHIP, "pwr on seq......\n");
278
279     //Wholechip FM Power Up: step 1, mt6620_off_2_longANA
280     if (FM_LOCK(cmd_buf_lock)) 
281                 return (-FM_ELOCK);
282     pkt_size = mt6620_off_2_longANA_1(cmd_buf, TX_BUF_SIZE);
283     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL);
284     FM_UNLOCK(cmd_buf_lock);
285
286     if (ret) {
287         WCN_DBG(FM_ALT | CHIP, "mt6620_off_2_longANA_1 failed\n");
288         return ret;
289     }
290
291     Delayms(100);
292
293     if (FM_LOCK(cmd_buf_lock)) 
294                 return (-FM_ELOCK);
295     pkt_size = mt6620_off_2_longANA_2(cmd_buf, TX_BUF_SIZE);
296     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL);
297     FM_UNLOCK(cmd_buf_lock);
298
299     if (ret) {
300         WCN_DBG(FM_ALT | CHIP, "mt6620_off_2_longANA_2 failed\n");
301         return ret;
302     }
303
304     Delayms(50);
305
306    // *chip_id = 0x6620;
307    // *device_id = 0x6620;
308    // WCN_DBG(FM_NTC | CHIP, "chip_id:0x%04x\n", 0x6620);
309
310     //Wholechip FM Power Up: step 2, FM Digital Init: fm_rgf_maincon
311     if (FM_LOCK(cmd_buf_lock)) 
312                 return (-FM_ELOCK);
313     pkt_size = mt6620_pwrup_digital_init_1(cmd_buf, TX_BUF_SIZE);
314     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL);
315     FM_UNLOCK(cmd_buf_lock);
316
317     if (ret) {
318         WCN_DBG(FM_ALT | CHIP, "mt6620_pwrup_digital_init_2 failed\n");
319         return ret;;
320     }
321
322     Delayms(10);
323
324     if (FM_LOCK(cmd_buf_lock)) 
325                 return (-FM_ELOCK);
326     pkt_size = mt6620_pwrup_digital_init_2(cmd_buf, TX_BUF_SIZE);
327     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL);
328     FM_UNLOCK(cmd_buf_lock);
329
330     if (ret) {
331         WCN_DBG(FM_ALT | CHIP, "mt6620_pwrup_digital_init_2 failed\n");
332         return ret;;
333     }
334
335     Delayms(10);
336
337     if (FM_LOCK(cmd_buf_lock)) 
338                 return (-FM_ELOCK);
339     pkt_size = mt6620_pwrup_digital_init_3(cmd_buf, TX_BUF_SIZE);
340     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL);
341     FM_UNLOCK(cmd_buf_lock);
342
343     if (ret) {
344         WCN_DBG(FM_ALT | CHIP, "mt6620_pwrup_digital_init_3 failed\n");
345         return ret;;
346     }
347 #ifdef FM_DIGITAL_INPUT
348   #ifdef MT6573 //for MT6573
349                 if(get_chip_eco_ver() == CHIP_E1){
350                         ret = mt6620_I2s_Setting(MT6620_I2S_ON, MT6620_I2S_MASTER, MT6620_I2S_48K);
351                 }else{
352                         ret = mt6620_I2s_Setting(MT6620_I2S_ON, MT6620_I2S_SLAVE, MT6620_I2S_48K);
353                 }
354   #else
355                 ret = mt6620_I2s_Setting(MT6620_I2S_ON, MT6620_I2S_SLAVE, MT6620_I2S_48K);
356   #endif
357                 if(ret){
358                         WCN_DBG(FM_ERR |CHIP,"pwron set I2S on error\n");
359                         return ret;
360                 }
361                 //we will disable 6620 fm chip analog output when use I2S path, set 0x3A bit2 = 0
362                 //mt6620_set_bits(0x3A, 0, MASK(2));
363                 WCN_DBG(FM_NTC |CHIP,"pwron set I2S on ok\n");
364 #endif
365
366     mt6620_hw_info.eco_ver = (fm_s32)mtk_wcn_wmt_hwver_get();
367     WCN_DBG(FM_DBG | CHIP, "pwr on seq ok\n");
368     return ret;
369 }
370 static fm_s32 mt6620_PowerUpTx(void)
371 {
372     fm_s32 ret = 0;
373     fm_u16 pkt_size;
374     fm_u16 dataRead;
375
376     WCN_DBG(FM_DBG | CHIP, "pwr on Tx seq......\n");
377
378     if (FM_LOCK(cmd_buf_lock)) 
379                 return (-FM_ELOCK);
380     pkt_size = mt6620_off_2_tx_shortANA(cmd_buf, TX_BUF_SIZE);
381     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL);
382     FM_UNLOCK(cmd_buf_lock);
383
384     if (ret) {
385         WCN_DBG(FM_ALT | CHIP, "mt6620_off_2_tx_shortANA failed\n");
386         return ret;
387     }
388
389
390     mt6620_read(0x62, &dataRead);
391         WCN_DBG(FM_NTC | CHIP, "Tx on chipid=%x\n",dataRead);
392     
393     if (FM_LOCK(cmd_buf_lock)) 
394                 return (-FM_ELOCK);
395     pkt_size = mt6620_dig_init(cmd_buf, TX_BUF_SIZE);
396     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL);
397     FM_UNLOCK(cmd_buf_lock);
398
399     if (ret) {
400         WCN_DBG(FM_ALT | CHIP, "mt6620_dig_init failed\n");
401         return ret;
402     }
403     //get temprature
404     if(mtk_wcn_wmt_therm_ctrl(WMTTHERM_ENABLE) != fm_true)
405     {
406                 WCN_DBG(FM_ERR | MAIN, "wmt_therm_ctrl, WMTTHERM_ENABLE failed\n");
407        ret = -FM_ELINK;
408        return ret;
409     }
410 #ifdef FM_DIGITAL_INPUT
411                 ret = mt6620_I2s_Setting(MT6620_I2S_ON, MT6620_I2S_SLAVE, MT6620_I2S_48K);
412                 if(ret){
413                         WCN_DBG(FM_ERR |CHIP,"pwron tx set I2S on error\n");
414                         return ret;
415                 }
416                 //we will disable 6620 fm chip analog output when use I2S path, set 0x3A bit2 = 0
417                 //mt6620_set_bits(0x3A, 0, MASK(2));
418                 WCN_DBG(FM_NTC |CHIP,"pwron set I2S on ok\n");
419 #endif
420
421     WCN_DBG(FM_DBG | CHIP, "pwr on tx seq ok\n");
422     return ret;
423 }
424
425 static fm_s32 mt6620_PowerDown(void)
426 {
427     fm_s32 ret = 0;
428     fm_u16 pkt_size;
429
430     WCN_DBG(FM_DBG | CHIP, "pwr down seq\n");
431
432    // mt6620_RampDown();
433
434     if (FM_LOCK(cmd_buf_lock)) 
435                 return (-FM_ELOCK);
436     pkt_size = mt6620_pwrdown(cmd_buf, TX_BUF_SIZE);
437     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL);
438     FM_UNLOCK(cmd_buf_lock);
439
440     if (ret) {
441         WCN_DBG(FM_ALT | CHIP, "mt6620_pwrdown failed\n");
442         return ret;
443     }
444
445     return ret;
446 }
447
448 static fm_s32 mt6620_PowerDownTx(void)
449 {
450     fm_s32 ret = 0;
451
452    if(mtk_wcn_wmt_therm_ctrl(WMTTHERM_DISABLE) != fm_true)
453    {
454            WCN_DBG(FM_ERR | MAIN, "wmt_therm_ctrl, WMTTHERM_DISABLE failed\n");
455            ret = -FM_ELINK;
456    }
457
458     return ret;
459 }
460
461 static fm_bool MT6620_SetFreq_Tx(fm_u16 freq)
462 {
463     fm_s32 ret = 0;
464     fm_u16 pkt_size;
465
466     fm_cb_op->cur_freq_set(freq);
467     //start tune
468     if (FM_LOCK(cmd_buf_lock)) 
469                 return (-FM_ELOCK);
470     pkt_size = mt6620_tune_tx(cmd_buf, TX_BUF_SIZE, freq);
471     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_TUNE, SW_RETRY_CNT, TUNE_TIMEOUT, NULL);
472     FM_UNLOCK(cmd_buf_lock);
473
474     if (ret) {
475         WCN_DBG(FM_ALT | CHIP, "mt6620_tune_tx failed\n");
476         return ret;;
477     }
478
479         Delayms(125);
480
481     WCN_DBG(FM_DBG | CHIP, "mt6620_tune_tx to %d ok\n", freq);
482
483     return fm_true;
484 }
485
486 /*
487  * fm_print_curCQI -- print cur freq's CQI
488  * @cur_freq, current frequency
489  * If OK, return 0, else error code
490  */
491 static fm_s32 mt6620_print_curCQI(fm_u16 cur_freq)
492 {
493     fm_s32 ret = 0;
494     fm_u16 rssi = 0;
495     fm_u16 pamd = 0;
496     fm_u16 mr = 0;
497
498     if((ret = mt6620_write(FM_MAIN_PGSEL, FM_PG0)))
499         return ret;
500     if((ret = mt6620_read(FM_RSSI_IND, &rssi)))
501         return ret;
502     if((ret = mt6620_read(FM_ADDR_PAMD, &pamd)))
503         return ret;
504     if((ret = mt6620_read(FM_MR_IND, &mr)))
505         return ret;
506     
507     WCN_DBG(FM_NTC |CHIP,"FREQ=%d, RSSI=0x%04x, PAMD=0x%04x, MR=0x%04x\n", (fm_s32)cur_freq, rssi, pamd, mr);
508     return ret;    
509 }
510
511 static fm_bool mt6620_SetFreq(fm_u16 freq)
512 {
513     fm_s32 ret = 0;
514     fm_s32 hl_side = -1;
515     fm_s32 freq_avoid = -1;
516     fm_u16 pkt_size;
517
518     fm_cb_op->cur_freq_set(freq);
519
520         if((ret = MT6620_HL_Side_Adj(freq, &hl_side)))
521                 return ret;
522         WCN_DBG(FM_NTC |CHIP,"%s, [hl_side=%d]\n", __func__, hl_side);
523         
524         if((ret = MT6620_ADPLL_Freq_Avoid(freq, &freq_avoid)))
525                 return ret;
526         WCN_DBG(FM_NTC |CHIP,"%s, adpll [freq_avoid=%d]\n", __func__, freq_avoid);
527         
528 //      hw_ver = mtk_wcn_wmt_hwver_get();
529         if(hw_ver >= WMTHWVER_MT6620_E3)
530         {
531                 if((ret = MT6620_MCU_Freq_Avoid(freq, &freq_avoid)))
532                         return ret;
533                 WCN_DBG(FM_NTC |CHIP,"%s, mcu [freq_avoid=%d]\n", __func__, freq_avoid);
534         }
535         else
536         {
537                 WCN_DBG(FM_NTC |CHIP,"%s, no need do mcu freq avoid[hw_ver=%d]\n", __func__, hw_ver);
538         }
539         
540     //start tune
541     if (FM_LOCK(cmd_buf_lock)) 
542                 return (-FM_ELOCK);
543     pkt_size = mt6620_tune_1(cmd_buf, TX_BUF_SIZE, freq);
544     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_TUNE, SW_RETRY_CNT, TUNE_TIMEOUT, NULL);
545     FM_UNLOCK(cmd_buf_lock);
546
547     if (ret) {
548         WCN_DBG(FM_ALT | CHIP, "mt6620_tune_1 failed\n");
549         return ret;;
550     }
551
552     Delayms(200);
553
554     if (FM_LOCK(cmd_buf_lock)) 
555                 return (-FM_ELOCK);
556     pkt_size = mt6620_tune_2(cmd_buf, TX_BUF_SIZE, freq);
557     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_TUNE, SW_RETRY_CNT, TUNE_TIMEOUT, NULL);
558     FM_UNLOCK(cmd_buf_lock);
559
560     if (ret) {
561         WCN_DBG(FM_ALT | CHIP, "mt6620_tune_2 failed\n");
562         return ret;;
563     }
564
565     Delayms(35);
566
567     if (FM_LOCK(cmd_buf_lock)) 
568                 return (-FM_ELOCK);
569     pkt_size = mt6620_tune_3(cmd_buf, TX_BUF_SIZE, freq);
570     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_TUNE, SW_RETRY_CNT, TUNE_TIMEOUT, NULL);
571     FM_UNLOCK(cmd_buf_lock);
572
573     if (ret) {
574         WCN_DBG(FM_ALT | CHIP, "mt6620_tune_3 failed\n");
575         return ret;;
576     }
577
578     ret = mt6620_print_curCQI(freq);
579     WCN_DBG(FM_DBG | CHIP, "set freq to %d ok\n", freq);
580
581     return fm_true;
582 }
583
584
585 static fm_s32 mt6620_TxScan_SetFreq(fm_u16 freq)
586 {
587     fm_s32 ret = 0;
588     fm_u16 pkt_size = 0;
589
590     WCN_DBG(FM_NTC | CHIP,"+%s():[freq=%d]\n", __func__, freq);
591     if (FM_LOCK(cmd_buf_lock)) 
592                 return (-FM_ELOCK);
593     
594     pkt_size = mt6620_tune_txscan(cmd_buf, TX_BUF_SIZE, freq);
595     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_TUNE, SW_RETRY_CNT, TUNE_TIMEOUT, NULL);
596     FM_UNLOCK(cmd_buf_lock);
597     
598     FM_UNLOCK(cmd_buf_lock);
599     WCN_DBG(FM_NTC | CHIP,"-%s():[ret=%d]\n", __func__, ret);
600     return ret;
601 }
602
603 static fm_s32 mt6620_TxScan_GetCQI(fm_s16 *pRSSI, fm_s16 *pPAMD, fm_s16 *pMR)
604 {
605     fm_s32 cnt = 0;
606     fm_s32 ret = 0;
607         fm_s16 tmp_reg = 0;
608         fm_s16 aRSSI = 0;
609         fm_s16 aPAMD = 0;
610         fm_s16 aMR = 0;
611         
612     WCN_DBG(FM_NTC | CHIP,"+%s():\n", __func__);
613
614         if((pRSSI == NULL) || (pPAMD == NULL) || (pMR == NULL)){
615         WCN_DBG(FM_ERR | CHIP,"%s():para error, [pRSSI=%p],[aPAMD=%p],[pMR=%p]\n", 
616             __func__, pRSSI, pPAMD, pMR);
617         ret = -FM_EPARA;
618                 goto out;
619         }
620         
621         for(cnt = 0; cnt < 8; cnt++)
622         {
623                 Delayms(3);
624                 if((ret = mt6620_read(FM_RSSI_IND, &tmp_reg)))
625             goto out;
626                 tmp_reg = tmp_reg&0x03ff;
627                 tmp_reg = (tmp_reg > 511) ? ((fm_s16)(tmp_reg-1024)) : tmp_reg;
628                 aRSSI += tmp_reg;
629                 
630                 if((ret = mt6620_read(FM_ADDR_PAMD, &tmp_reg)))
631             goto out;
632                 tmp_reg = tmp_reg&0x00ff;
633                 tmp_reg = (tmp_reg > 127) ? ((fm_s16)(tmp_reg-256)) : tmp_reg;
634                 aPAMD += tmp_reg;
635                 
636                 if((ret = mt6620_read(FM_MR_IND, &tmp_reg)))
637             goto out;
638                 tmp_reg = tmp_reg&0x01ff;
639                 tmp_reg = (tmp_reg > 255) ? ((fm_s16)(tmp_reg-512)) : tmp_reg;
640                 aMR += tmp_reg;
641         }
642
643         *pRSSI = aRSSI>>3;
644         *pPAMD = aPAMD>>3;
645         *pMR = aMR>>3;
646
647     WCN_DBG(FM_NTC | CHIP,"%s():[RSSI=%d],[PAMD=%d],[MR=%d]\n", 
648             __func__, *pRSSI, *pPAMD, *pMR);
649     
650 out:
651     WCN_DBG(FM_NTC | CHIP,"-%s():[ret=%d]\n", __func__, ret);
652     return ret;
653 }
654
655 static fm_s32 mt6620_TxScan_IsEmptyChannel(fm_s16 RSSI, fm_s16 PAMD, fm_s16 MR, fm_s32 *empty)
656 {
657     fm_s32 ret = 0;
658     
659     WCN_DBG(FM_NTC | CHIP,"+%s():[RSSI=%d],[PAMD=%d],[MR=%d]\n", __func__, RSSI, PAMD, MR);
660
661     if(empty == NULL)
662     {
663         WCN_DBG(FM_NTC | CHIP,"invalid pointer [empty=0x%x]!\n", (fm_u32)empty);
664         ret = -FM_EPARA;
665         goto out;
666     }
667
668     *empty = fm_true; 
669         if(RSSI > FM_TXSCAN_RSSI_TH){
670             *empty = fm_false;
671         goto out;
672         }
673
674         if(PAMD < FM_TXSCAN_PAMD_TH){
675                 *empty = fm_false;
676         goto out;
677         }
678
679         if(MR < FM_TXSCAN_MR_TH){
680                 *empty = fm_false;
681         goto out;
682         }
683
684 out:
685     WCN_DBG(FM_NTC | CHIP,"-%s():[ret=%d]\n", __func__, ret);
686     return ret;
687 }
688
689 static fm_s32 mt6620_TxScan(fm_u16 min_freq, 
690                                                                 fm_u16 max_freq,
691                                         fm_u16 *pFreq,
692                                         fm_u16 *pScanTBL,
693                                         fm_u16 *ScanTBLsize,
694                                         fm_u16 scandir,
695                                         fm_u16 space)
696 {
697         fm_s32 ret = 0;
698         fm_u16 freq = *pFreq;
699         fm_u16 scan_cnt = *ScanTBLsize;
700         fm_u16 cnt = 0; 
701         fm_s16 rssi = 0;
702         fm_s16 pamd = 0;
703         fm_s16 mr = 0;
704         fm_s32 counter = 0;
705     fm_s32 empty = -1;
706     fm_s32 step;
707
708     WCN_DBG(FM_NTC | CHIP,"+%s():\n", __func__);
709     
710     if((!pScanTBL) || (*ScanTBLsize < FM_TX_SCAN_MIN) || (*ScanTBLsize >  FM_TX_SCAN_MAX))
711     {
712         WCN_DBG(FM_ERR | CHIP,"+%s():invalid scan table\n", __func__);
713         ret = -FM_EPARA;
714         goto out;
715     }
716
717     WCN_DBG(FM_NTC | CHIP, "[freq=%d], [max_freq=%d],[min_freq=%d],[scan BTL size=%d],[scandir=%d],[space=%d]\n", 
718                         *pFreq, max_freq, min_freq, *ScanTBLsize, scandir, space);
719
720         cnt = 0;
721    /* if (space == MT6620_FM_SPACE_100K) {
722         step = 1;
723     } else if (space == MT6620_FM_SPACE_50K) {
724         step = 5;
725     } else if (space == MT6620_FM_SPACE_200K) {
726         step = 2;
727     } else {
728         //default
729         step = 1;
730     }*/
731     step = space;
732         while(!(!(cnt < scan_cnt) || (freq > max_freq) || (freq < min_freq))){
733                 //MT6620_RampDown();
734                 //Set desired channel, tune to the channel, and perform fast AGC
735                 counter++; //just for debug
736                 
737                 ret = mt6620_TxScan_SetFreq(freq);
738                 if(ret){
739             WCN_DBG(FM_ERR | CHIP,"%s():set freq failed\n", __func__);
740                         goto out;
741                 }
742                 
743                 //wait 8~10ms for RF setting
744                 Delayms(10);
745                 //wait 4 AAGC period for AAGC setting, AAGC period = 1024/480k = 2.13ms
746                 Delayms(9);
747                 
748                 ret = mt6620_TxScan_GetCQI(&rssi, &pamd, &mr);
749                 if(ret){
750             WCN_DBG(FM_ERR | CHIP,"%s():get CQI failed\n", __func__);
751                         goto out;
752                 }
753
754                 ret = mt6620_TxScan_IsEmptyChannel(rssi, pamd, mr, &empty);
755                 if(!ret){
756             if((empty == fm_true) && ((freq < FM_TX_SCAN_HOLE_LOW) || (freq > FM_TX_SCAN_HOLE_HIGH))){
757                 *(pScanTBL + cnt) = freq; //strore the valid empty channel 
758                             cnt++;
759                 WCN_DBG(FM_NTC | CHIP,"empty channel:[freq=%d] [cnt=%d]\n", freq, cnt);
760             }                   
761                 }else{ 
762                     WCN_DBG(FM_ERR | CHIP,"%s():IsEmptyChannel failed\n", __func__);
763                         goto out;
764         }
765
766                 if(scandir == FM_TX_SCAN_UP){
767             if(freq == FM_TX_SCAN_HOLE_LOW){
768                 freq += (FM_TX_SCAN_HOLE_HIGH - FM_TX_SCAN_HOLE_LOW + step);
769             }else{
770                 freq += step;
771             }
772                 }else if(scandir == FM_TX_SCAN_DOWN){
773                     if(freq == FM_TX_SCAN_HOLE_HIGH){
774                 freq -= (FM_TX_SCAN_HOLE_HIGH - FM_TX_SCAN_HOLE_LOW + step);
775             }else{
776                 freq -= step;
777             }
778                 }else{
779             WCN_DBG(FM_ERR | CHIP,"%s():scandir para error\n", __func__);
780                         ret = -FM_EPARA;
781             goto out;
782                 }
783         }
784
785         *ScanTBLsize = cnt;
786         *pFreq = *(pScanTBL + cnt);
787         WCN_DBG(FM_NTC | CHIP, "completed, [cnt=%d],[freq=%d],[counter=%d]\n", cnt, freq, counter);
788     
789 out:
790     WCN_DBG(FM_NTC | CHIP,"-%s():[ret=%d]\n", __func__, ret);
791     return ret;
792 }
793
794 /*
795 * mt6620_Seek
796 * @pFreq - IN/OUT parm, IN start freq/OUT seek valid freq
797 * @seekdir - 0:up, 1:down
798 * @space - 1:50KHz, 2:100KHz, 4:200KHz
799 * return fm_true:seek success; fm_false:seek failed
800 */
801 static fm_bool mt6620_Seek(fm_u16 min_freq, fm_u16 max_freq, fm_u16 *pFreq, fm_u16 seekdir, fm_u16 space)
802 {
803     fm_s32 ret = 0;
804     fm_u16 pkt_size,temp;
805
806     mt6620_RampDown();
807     mt6620_read(0x9C, &temp);
808     mt6620_Mute(fm_true);
809
810     if (FM_LOCK(cmd_buf_lock)) 
811                 return (-FM_ELOCK);
812     pkt_size = mt6620_seek_1(cmd_buf, TX_BUF_SIZE, seekdir, space, max_freq, min_freq);
813     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SEEK | FLAG_SEEK_DONE, SW_RETRY_CNT, SEEK_TIMEOUT, mt6620_get_read_result);
814     FM_UNLOCK(cmd_buf_lock);
815
816     if (!ret && res) {
817         *pFreq = res->seek_result;
818         fm_cb_op->cur_freq_set(*pFreq);
819     } else {
820         WCN_DBG(FM_ALT | CHIP, "mt6620_seek_1 failed\n");
821         return ret;
822     }
823
824     Delayms(35);
825
826     if (FM_LOCK(cmd_buf_lock)) 
827                 return (-FM_ELOCK);
828     pkt_size = mt6620_seek_2(cmd_buf, TX_BUF_SIZE, seekdir, space, max_freq, min_freq);
829     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SEEK | FLAG_SEEK_DONE, SW_RETRY_CNT, SEEK_TIMEOUT, mt6620_get_read_result);
830     FM_UNLOCK(cmd_buf_lock);
831
832     if (ret) {
833         WCN_DBG(FM_ALT | CHIP, "mt6620_seek_2 failed\n");
834         return ret;
835     }
836
837     //get the result freq
838     WCN_DBG(FM_NTC | CHIP, "seek, result freq:%d\n", *pFreq);
839         if((temp&0x0008) == 0)
840         {
841     mt6620_Mute(fm_false);
842         }
843
844     return fm_true;
845 }
846
847 static fm_bool mt6620_Scan(fm_u16 min_freq, fm_u16 max_freq, fm_u16 *pFreq, fm_u16 *pScanTBL,
848                            fm_u16 *ScanTBLsize, fm_u16 scandir, fm_u16 space)
849 {
850     fm_s32 ret = 0;
851     fm_u16 pkt_size,temp;
852     fm_u16 offset = 0;
853     fm_u16 tmp_scanTBLsize = *ScanTBLsize;
854
855     if ((!pScanTBL) || (tmp_scanTBLsize == 0)) {
856         WCN_DBG(FM_ALT | CHIP, "scan, failed:invalid scan table\n");
857         return fm_false;
858     }
859
860     WCN_DBG(FM_DBG | CHIP, "start freq: %d, max_freq:%d, min_freq:%d, scan BTL size:%d, scandir:%d, space:%d\n", *pFreq, max_freq, min_freq, *ScanTBLsize, scandir, space);
861
862     mt6620_RampDown();
863     mt6620_read(0x9C, &temp);
864     mt6620_Mute(fm_true);
865
866     if (FM_LOCK(cmd_buf_lock)) 
867                 return (-FM_ELOCK);
868     pkt_size = mt6620_scan_1(cmd_buf, TX_BUF_SIZE, scandir, space, max_freq, min_freq);
869     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SCAN | FLAG_SCAN_DONE, SW_RETRY_CNT, SCAN_TIMEOUT, mt6620_get_read_result);
870     FM_UNLOCK(cmd_buf_lock);
871
872     if (!ret && res) {
873         fm_memcpy(pScanTBL, res->scan_result, sizeof(fm_u16)*FM_SCANTBL_SIZE);
874         WCN_DBG(FM_INF | CHIP, "Rx Scan Result:\n");
875
876         for (offset = 0; offset < tmp_scanTBLsize; offset++) {
877             WCN_DBG(FM_INF | CHIP, "%d: %04x\n", (fm_s32)offset, *(pScanTBL + offset));
878         }
879
880         *ScanTBLsize = tmp_scanTBLsize;
881     } else {
882         WCN_DBG(FM_ALT | CHIP, "mt6620_scan_1 failed\n");
883         return ret;
884     }
885
886     Delayms(35);
887
888     if (FM_LOCK(cmd_buf_lock)) 
889                 return (-FM_ELOCK);
890     pkt_size = mt6620_scan_2(cmd_buf, TX_BUF_SIZE, scandir, space, max_freq, min_freq);
891     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SEEK | FLAG_SEEK_DONE, SW_RETRY_CNT, SEEK_TIMEOUT, mt6620_get_read_result);
892     FM_UNLOCK(cmd_buf_lock);
893
894     if (ret) {
895         WCN_DBG(FM_ALT | CHIP, "mt6620_scan_2 failed\n");
896         return ret;
897     }
898
899         if((temp&0x0008) == 0)
900         {
901     mt6620_Mute(fm_false);
902         }
903
904     return fm_true;
905 }
906
907 /*
908  * mt6620_GetCurRSSI - get current freq's RSSI value
909  * RS=RSSI
910  * If RS>511, then RSSI(dBm)= (RS-1024)/16*6
911  *                                 else RSSI(dBm)= RS/16*6
912  */
913 static fm_s32 mt6620_GetCurRSSI(fm_s32 *pRSSI)
914 {
915     fm_u16 tmp_reg;
916
917     mt6620_read(FM_RSSI_IND, &tmp_reg);
918     tmp_reg = tmp_reg & 0x03ff;
919
920     if (pRSSI) {
921         *pRSSI = (tmp_reg > 511) ? (((tmp_reg - 1024) * 6) >> 4) : ((tmp_reg * 6) >> 4);
922         WCN_DBG(FM_DBG | CHIP, "rssi:%d, dBm:%d\n", tmp_reg, *pRSSI);
923     } else {
924         WCN_DBG(FM_ERR | CHIP, "get rssi para error\n");
925         return -FM_EPARA;
926     }
927
928     return 0;
929 }
930
931 static fm_s32 MT6620_Fast_SetFreq(fm_u16 freq)
932 {
933     fm_s32 ret = 0;
934     fm_u16 pkt_size = 0;
935
936     if (FM_LOCK(cmd_buf_lock)) 
937                 return (-FM_ELOCK);
938     pkt_size = mt6620_fast_tune(cmd_buf, TX_BUF_SIZE, freq);
939     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_TUNE, SW_RETRY_CNT, SEEK_TIMEOUT, mt6620_get_read_result);
940     FM_UNLOCK(cmd_buf_lock);
941
942     if (ret) {
943         WCN_DBG(FM_ALT | CHIP, "mt6620_fast_tune failed\n");
944         return ret;
945     }
946     return ret;
947 }
948
949 /*
950  * mt6620_get_RSSI - set freq and return RSSI value
951 *
952  */
953 static fm_s32 mt6620_GetFreqCQI(fm_u16 freq,fm_s32 *pRSSI)
954 {
955         if(MT6620_Fast_SetFreq(freq))
956         {
957                 mt6620_GetCurRSSI(pRSSI);
958         }
959
960     return 0;
961 }
962
963 static fm_u8 mt6620_vol_tbl[16] = {
964     0, 1, 2, 3, 4, 5, 7, 9, 11, 14, 17, 21, 25, 30, 36, 43
965 };
966 static fm_s32 mt6620_SetVol(fm_u8 vol)
967 {
968     fm_s32 ret = 0;
969     fm_u8 tmp_vol;// = vol & 0x3f;
970
971     vol = (vol > 15) ? 15 : vol;
972     tmp_vol = mt6620_vol_tbl[vol] & 0x3f;
973     if (tmp_vol > MT6620_VOL_MAX)
974         tmp_vol = MT6620_VOL_MAX;
975
976     ret = mt6620_set_bits(0x9C, (tmp_vol << 8), 0xC0FF);
977
978     if (ret) {
979         WCN_DBG(FM_ERR | CHIP, "Set vol=%d Failed\n", tmp_vol);
980         return ret;
981     } else {
982         WCN_DBG(FM_DBG | CHIP, "Set vol=%d OK\n", tmp_vol);
983     }
984
985     return 0;
986 }
987
988 static fm_s32 mt6620_GetVol(fm_u8 *pVol)
989 {
990     fm_s32 ret = 0;
991     fm_u16 tmp_reg;
992
993     FMR_ASSERT(pVol);
994
995     ret = mt6620_read(0x9C, &tmp_reg);
996
997     if (ret) {
998         *pVol = 0;
999         WCN_DBG(FM_ERR | CHIP, "Get vol Failed\n");
1000         return ret;
1001     } else {
1002         *pVol = (tmp_reg >> 8) & 0x3f;
1003                 if(*pVol == MT6620_VOL_MAX)
1004                         *pVol = 15;
1005                 else
1006                         *pVol = (*pVol/3);
1007         WCN_DBG(FM_DBG | CHIP, "Get vol=%d OK\n", *pVol);
1008     }
1009
1010     return 0;
1011
1012 }
1013
1014 static fm_s32 mt6620_dump_reg(void)
1015 {
1016         fm_s32 i;
1017         fm_u16 TmpReg;
1018         for(i=0; i<0xff; i++)
1019         {
1020                 mt6620_read(i, &TmpReg);
1021                 WCN_DBG(FM_NTC | CHIP, "0x%02x=0x%04x\n",i,TmpReg);
1022         }
1023         return 0;
1024 }
1025
1026
1027 static fm_bool mt6620_GetMonoStereo(fm_u16 *pMonoStereo)
1028 {
1029     fm_u16 tmp_reg;
1030
1031     mt6620_write(FM_MAIN_PGSEL, 0x0001);
1032
1033     if (pMonoStereo) {
1034         mt6620_read(0xF8, &tmp_reg);
1035         *pMonoStereo = (tmp_reg & 0x0400) >> 10;
1036     } else {
1037         WCN_DBG(FM_ERR | CHIP, "MonoStero: para err\n");
1038         return fm_false;
1039     }
1040
1041     mt6620_write(FM_MAIN_PGSEL, 0x0000);
1042
1043     WCN_DBG(FM_DBG | CHIP, "MonoStero:0x%04x\n", *pMonoStereo);
1044     return fm_true;
1045 }
1046
1047 /*
1048  * MT6620_SetMonoStereo
1049  * Force set to stero/mono mode
1050  * @MonoStereo -- 0, auto; 1, force mono
1051  * If success, return 0; else error code
1052  */
1053 static fm_s32 MT6620_SetMonoStereo(fm_s32 MonoStereo)
1054 {
1055     fm_u16 tmp_reg;
1056     fm_s32 ret = 0;
1057     
1058     if((ret = mt6620_write(FM_MAIN_PGSEL, FM_PG1)))
1059         goto out;
1060
1061     tmp_reg = MonoStereo ? BITn(1) : 0; //MonoStereo, 1: force mono; 0:auto
1062     if((ret = mt6620_set_bits(FM_STEROMONO_CTR, tmp_reg, MASK(1))))//set E0 D1=0
1063         goto out;
1064     
1065     if((ret = mt6620_write(FM_MAIN_PGSEL, FM_PG0)))
1066         goto out;
1067     
1068     WCN_DBG(FM_DBG | CHIP,"set to %s\n", MonoStereo ? "auto" : "force mono");
1069     
1070 out:
1071     return ret;
1072 }
1073
1074 static fm_s32 mt6620_GetCapArray(fm_s32 *ca)
1075 {
1076     fm_u16 dataRead;
1077
1078     FMR_ASSERT(ca);
1079
1080     mt6620_read(0x26, &dataRead);
1081     *ca = dataRead;
1082
1083     return 0;
1084 }
1085
1086 /*
1087  * mt6620_GetCurPamd - get current freq's PAMD value
1088  * PA=PAMD
1089  * If PA>511 then PAMD(dB)=  (PA-1024)/16*6,
1090  *                              else PAMD(dB)=PA/16*6
1091  */
1092 static fm_bool mt6620_GetCurPamd(fm_u16 *pPamdLevl)
1093 {
1094     fm_u16 tmp_reg;
1095     fm_u16 dBvalue=0,valid_cnt=0;
1096     fm_s32 i,total=0;
1097
1098     for (i = 0; i < 8; i++) 
1099     {
1100             if (mt6620_read(FM_ADDR_PAMD, &tmp_reg))
1101             {
1102                 *pPamdLevl = 0;
1103                 return fm_false;
1104                 }
1105
1106             tmp_reg &= 0x00FF;
1107             dBvalue = (tmp_reg>127) ? ((256-tmp_reg)*6/16):0;
1108                 if(dBvalue != 0)
1109                 {
1110                         total += dBvalue;
1111                         valid_cnt++;
1112                         WCN_DBG(FM_DBG | CHIP, "[%d]PAMD=%d\n",i,dBvalue);
1113                 }
1114         Delayms(3);
1115         }
1116         if(valid_cnt != 0)
1117         {
1118             *pPamdLevl = total/valid_cnt;
1119         }
1120         else
1121         {
1122                 *pPamdLevl = 0;
1123         }
1124     WCN_DBG(FM_DBG | CHIP,"PamdLevl=%d\n", *pPamdLevl);
1125     return fm_true;
1126 }
1127
1128 static fm_s32 mt6620_ScanStop(void)
1129 {
1130     return fm_force_active_event(FLAG_SCAN);
1131 }
1132
1133 static fm_s32 mt6620_SeekStop(void)
1134 {
1135     return fm_force_active_event(FLAG_SEEK);
1136 }
1137
1138 /*
1139  * mt6620_I2s_Setting - set the I2S state on MT6620
1140  * @onoff - I2S on/off
1141  * @mode - I2S mode: Master or Slave
1142  *
1143  * Return:0, if success; error code, if failed
1144  */
1145 static fm_s32 mt6620_I2s_Setting(fm_s32 onoff, fm_s32 mode, fm_s32 sample)
1146 {
1147     fm_u16 tmp_state = 0;
1148     fm_u16 tmp_mode = 0;
1149     fm_u16 tmp_sample = 0;
1150     fm_s32 ret = 0;
1151
1152     if (onoff == MT6620_I2S_ON) {
1153         tmp_state = 0x01; //I2S Frequency tracking on
1154         mt6620_i2s_inf.status = 1;
1155     } else if (onoff == MT6620_I2S_OFF) {
1156         tmp_state = 0x00; //I2S Frequency tracking off
1157         mt6620_i2s_inf.status = 0;
1158     } else {
1159         WCN_DBG(FM_ERR | CHIP, "%s():[onoff=%d]\n", __func__, onoff);
1160         ret = -FM_EPARA;
1161         goto out;
1162     }
1163
1164     if (mode == MT6620_I2S_MASTER) {
1165         tmp_mode = 0x03; //6620 as I2S master
1166         mt6620_i2s_inf.mode = 1;
1167     } else if (mode == MT6620_I2S_SLAVE) {
1168         tmp_mode = 0x0B; //6620 as I2S slave
1169         mt6620_i2s_inf.mode = 0;
1170     } else {
1171         WCN_DBG(FM_ERR | CHIP, "%s():[mode=%d]\n", __func__, mode);
1172         ret = -FM_EPARA;
1173         goto out;
1174     }
1175
1176     if (sample == MT6620_I2S_32K) {
1177         tmp_sample = 0x0000; //6620 I2S 32KHz sample rate
1178         mt6620_i2s_inf.rate = 32000;
1179     } else if (sample == MT6620_I2S_44K) {
1180         tmp_sample = 0x0800; //6620 I2S 44.1KHz sample rate
1181         mt6620_i2s_inf.rate = 44100;
1182     } else if (sample == MT6620_I2S_48K) {
1183         tmp_sample = 0x1000; //6620 I2S 48KHz sample rate
1184         mt6620_i2s_inf.rate = 48000;
1185     } else {
1186         WCN_DBG(FM_ERR | CHIP, "%s():[sample=%d]\n", __func__, sample);
1187         ret = -FM_EPARA;
1188         goto out;
1189     }
1190
1191     if ((ret = mt6620_set_bits(0x5F, tmp_sample, 0xE7FF)))
1192         goto out;
1193
1194     if ((ret = mt6620_write(0x9B, tmp_mode)))
1195         goto out;
1196
1197     if ((ret = mt6620_set_bits(0x56, tmp_state, 0xFF7F)))
1198         goto out;
1199
1200     WCN_DBG(FM_NTC | CHIP, "[onoff=%s][mode=%s][sample=%d](0)33KHz,(1)44.1KHz,(2)48KHz\n",
1201             (onoff == MT6620_I2S_ON) ? "On" : "Off",
1202             (mode == MT6620_I2S_MASTER) ? "Master" : "Slave",
1203             sample);
1204 out:
1205     return ret;
1206 }
1207 static fm_s32 mt6620_Tx_Support(fm_s32 *sup)
1208 {
1209         *sup=1;
1210         return 0;
1211 }
1212
1213 static fm_s32 mt6620_rdsTx_Support(fm_s32 *sup)
1214 {
1215         *sup=1;
1216         return 0;
1217 }
1218
1219 static fm_s32 MT6620_FMOverBT(fm_bool enable)
1220 {
1221     fm_s32 ret = 0;
1222     static fm_u16 state = 0;
1223     static fm_u16 mode = 0;
1224     static fm_u16 sample = 0;
1225     static fm_u16 inited = fm_false;
1226
1227     WCN_DBG(FM_NTC | CHIP,"+%s():\n", __func__);
1228     if(inited == fm_false)
1229     {
1230         // record priv val
1231         if((ret = mt6620_read(0x56, &state)))
1232             goto out;
1233         if((ret = mt6620_read(0x9B, &mode)))
1234             goto out;
1235         if((ret = mt6620_read(0x5F, &sample)))
1236             goto out;
1237         inited = fm_true;
1238         WCN_DBG(FM_NTC | CHIP,"init, record priv seetings\n");
1239     }
1240     
1241     if(enable == fm_true){
1242         //disable analog output when FM over BT
1243         if((ret = mt6620_set_bits(0x3A, 0, MASK(2))))
1244             goto out;
1245         //set FM over BT
1246         if((ret = mt6620_write(0x56, 0x0001)))
1247             goto out;
1248         if((ret = mt6620_write(0x9B, 0x000b)))
1249             goto out;
1250         if((ret = mt6620_write(0x5F, 0x1175)))
1251             goto out;
1252         WCN_DBG(FM_NTC | CHIP,"set FM via BT controller\n");
1253     }
1254     else if(enable == fm_false)
1255     {
1256         //enable analog output when FM normal mode
1257         if((ret = mt6620_set_bits(0x3A, BITn(2), MASK(2))))
1258             goto out;
1259         //recover to priv val
1260         if((ret = mt6620_write(0x56, state)))
1261             goto out;
1262         if((ret = mt6620_write(0x9B, mode)))
1263             goto out;
1264         if((ret = mt6620_write(0x5F, sample)))
1265             goto out;
1266         WCN_DBG(FM_NTC | CHIP,"set FM via Host\n");
1267     }
1268     else
1269     {
1270         WCN_DBG(FM_ERR | CHIP,"%s()\n", __func__);
1271         ret = -FM_EPARA;
1272         goto out;
1273     }
1274 out:
1275     WCN_DBG(FM_NTC | CHIP,"-%s():[ret=%d]\n", __func__, ret);
1276     return ret; 
1277 }
1278
1279 /*fm soft mute tune function*/
1280 static fm_s32 mt6620_soft_mute_tune(fm_u16 freq,fm_s32 *rssi,fm_bool *valid)
1281 {
1282     fm_s32 ret=0;
1283     fm_u16 pkt_size;    
1284     fm_s32 hilo_side = -1;    
1285     struct mt6620_fm_softmute_tune_cqi_t *p_cqi;
1286         fm_s32 RSSI=0, PAMD=0,MR=0, ATDC=0;
1287         fm_u32 PRX=0;
1288         fm_u16 softmuteGainLvl=0;
1289
1290         /*set hilo side first(f/w won't do this), need to check whether work if set before rampdown*/
1291         if((ret = MT6620_HL_Side_Adj(freq, &hilo_side)))
1292                 return ret;
1293         
1294         if (FM_LOCK(cmd_buf_lock)) return (-FM_ELOCK);
1295         pkt_size = mt6620_full_cqi_req(cmd_buf, TX_BUF_SIZE, freq, 1, 1);
1296         ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, SM_TUNE_TIMEOUT, mt6620_get_read_result);
1297         FM_UNLOCK(cmd_buf_lock);
1298
1299         if (!ret && res) 
1300         {
1301                 WCN_DBG(FM_NTC | CHIP, "smt cqi size %d\n", res->cqi[0]);
1302                 p_cqi = (struct mt6620_fm_softmute_tune_cqi_t*)&res->cqi[2];
1303                 // just for debug
1304                 WCN_DBG(FM_NTC | CHIP, "freq %d, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x\n", 
1305                         p_cqi->ch, 
1306                         p_cqi->rssi,
1307                         p_cqi->pamd,
1308                         p_cqi->mr,
1309                         p_cqi->atdc,
1310                         p_cqi->prx,
1311                         p_cqi->smg); 
1312                 RSSI = ((p_cqi->rssi & 0x03FF) >= 512) ? ((p_cqi->rssi & 0x03FF) - 1024) : (p_cqi->rssi & 0x03FF);
1313                 PAMD = ((p_cqi->pamd & 0xFF) >= 128) ? ((p_cqi->pamd & 0x0FF) - 256) : (p_cqi->pamd & 0x0FF);
1314                 MR = ((p_cqi->mr & 0x01FF) >= 256) ? ((p_cqi->mr & 0x01FF) - 512) : (p_cqi->mr & 0x01FF);
1315                 ATDC =((p_cqi->atdc & 0x0FFF) >= 2048) ? ((p_cqi->atdc & 0x0FFF) - 4096) : (p_cqi->atdc & 0x0FFF);
1316                 if(ATDC < 0)
1317                 {
1318                         ATDC = (~(ATDC)) - 1;//Get abs value of ATDC
1319                 }
1320                 PRX = (p_cqi->prx & 0x00FF);
1321                 softmuteGainLvl = p_cqi->smg;
1322                 //check if the channel is valid according to each CQIs
1323                 if((RSSI >= mt6620_fm_config.rx_cfg.long_ana_rssi_th) 
1324                  && (PAMD <= mt6620_fm_config.rx_cfg.pamd_th)
1325                  && (ATDC <= mt6620_fm_config.rx_cfg.atdc_th)
1326                  && (MR >= mt6620_fm_config.rx_cfg.mr_th)
1327                  && (PRX >= mt6620_fm_config.rx_cfg.prx_th)
1328                  && (softmuteGainLvl <= mt6620_fm_config.rx_cfg.smg_th))
1329                 {        
1330                         *valid = fm_true;
1331                 }
1332                 else
1333                 {
1334                         *valid = fm_false;
1335                 }
1336                 *rssi = RSSI;
1337         }
1338         else 
1339         {
1340                 WCN_DBG(FM_ALT | CHIP, "smt get CQI failed\n");
1341                 return fm_false;
1342         }
1343         WCN_DBG(FM_NTC | CHIP, "valid=%d\n",*valid);
1344         return fm_true;
1345 }
1346 static fm_s32 mt6620_i2s_info_get(fm_s32 *ponoff, fm_s32 *pmode, fm_s32 *psample)
1347 {
1348     FMR_ASSERT(ponoff);
1349     FMR_ASSERT(pmode);
1350     FMR_ASSERT(psample);
1351
1352     *ponoff = mt6620_i2s_inf.status;
1353     *pmode = mt6620_i2s_inf.mode;
1354     *psample = mt6620_i2s_inf.rate;
1355
1356     return 0;
1357 }
1358
1359 static fm_s32 mt6620_hw_info_get(struct fm_hw_info *req)
1360 {
1361     FMR_ASSERT(req);
1362
1363     req->chip_id = mt6620_hw_info.chip_id;
1364     req->eco_ver = mt6620_hw_info.eco_ver;
1365     req->patch_ver = mt6620_hw_info.patch_ver;
1366     req->rom_ver = mt6620_hw_info.rom_ver;
1367
1368     return 0;
1369 }
1370
1371 static fm_bool mt6620_em_test(fm_u16 group_idx, fm_u16 item_idx, fm_u32 item_value)
1372 {
1373         fm_s32 ret = 0;
1374         
1375         WCN_DBG(FM_NTC | CHIP,"+%s():[group_idx=%d],[item_idx=%d],[item_value=%d]\n", 
1376                 __func__, group_idx, item_idx, item_value);
1377         
1378         switch (group_idx){
1379                 case mono:
1380                         if((ret = mt6620_write(FM_MAIN_PGSEL, 0x01)))
1381                                 goto out;
1382
1383                         if(item_value == 1){
1384                                 if((ret = mt6620_set_bits(0xE0, 0x02, 0xFFFF)))
1385                                         goto out;
1386                         }else{
1387                                 if((ret = mt6620_set_bits(0xE0, 0x0, 0xFFFD)))
1388                                         goto out;
1389                         }
1390                         if((ret = mt6620_write(FM_MAIN_PGSEL, 0x0)))
1391                                 goto out;
1392                         break;
1393                 case stereo:
1394                         if((ret = mt6620_write(FM_MAIN_PGSEL, 0x01)))
1395                                 goto out;
1396                         if(item_value == 0){
1397                                 if((ret = mt6620_set_bits(0xE0, 0x0, 0xFFFD)))
1398                                         goto out;
1399                         }else{
1400                                 switch (item_idx){
1401                                         case Sblend_ON:
1402                                                 if((ret = mt6620_set_bits(0xD8, item_idx<<15, 0x7FFF)))
1403                                                         goto out;
1404                                                 break;
1405                                         case Sblend_OFF:
1406                                                 if((ret = mt6620_set_bits(0xD8, 0, 0x7FFF)))
1407                                                         goto out;
1408                                                 break;
1409                                 }
1410                         }
1411                         if((ret = mt6620_write(FM_MAIN_PGSEL, 0x0)))
1412                                 goto out;
1413                         break;
1414                 case RSSI_threshold:
1415                         if((ret = mt6620_set_bits(0xe0, item_value, 0xFC00)))
1416                                 goto out;
1417                         break;
1418                 case HCC_Enable:
1419                         if((ret = mt6620_write(FM_MAIN_PGSEL, 0x01)))
1420                                 goto out;
1421                         if(item_idx){
1422                                 if((ret = mt6620_set_bits(0xCF, 0x10, 0xFFFF)))
1423                                         goto out;
1424                         }else{
1425                                 if((ret = mt6620_set_bits(0xCF, 0x0, 0xFFEF)))
1426                                         goto out;
1427                         }
1428                         if((ret = mt6620_write(FM_MAIN_PGSEL, 0x0)))
1429                                 goto out;
1430                         break;
1431                 case PAMD_threshold:
1432                         if((ret = mt6620_set_bits(0xE1, item_value, 0xFF00)))
1433                                 goto out;
1434                         break;
1435                 case Softmute_Enable:
1436                         if((ret = mt6620_write(FM_MAIN_PGSEL, 0x01)))
1437                                 goto out;
1438                         if(item_idx){
1439                                 if((ret = mt6620_set_bits(0xCF, 0x0020, 0xFFFF))) //1:CF[5] = 1
1440                                         goto out; 
1441                         }else{
1442                                 if((ret = mt6620_set_bits(0xCF, 0x0000, 0xFFDF))) //1:CF[5] = 0
1443                                         goto out; 
1444                         }
1445                         if((ret = mt6620_write(FM_MAIN_PGSEL, 0x0)))
1446                                 goto out;
1447                         break;
1448                 case De_emphasis:
1449                         if((ret = mt6620_write(FM_MAIN_PGSEL, 0x01)))
1450                                 goto out;
1451                         if(item_idx == 2){
1452                                 if((ret = mt6620_set_bits(0xd4, 0x2000, 0xCFFF)))
1453                                         goto out;
1454                         }else if(item_idx == 1){
1455                                 if((ret = mt6620_set_bits(0xd4, 0x1000, 0xCFFF)))
1456                                         goto out;
1457                         }else if(item_idx == 0){
1458                                 if((ret = mt6620_set_bits(0xd4, 0x0000, 0xCFFF)))
1459                                         goto out;
1460                         }
1461                         if((ret = mt6620_write(FM_MAIN_PGSEL, 0x0)))
1462                                 goto out;
1463                         break;
1464                 case HL_Side:
1465                         if(item_idx == 2){
1466                                  //H-Side
1467                                 if((ret = mt6620_set_bits(0xCB, 0x11, 0xFFFE)))
1468                                         goto out;
1469                                 if((ret = mt6620_set_bits(0xF, 0x0400,  0xFBFF)))
1470                                         goto out;
1471                         }else if(item_idx == 1){
1472                                  //L-Side
1473                                 if((ret = mt6620_set_bits(0xCB, 0x10, 0xFFFE)))
1474                                         goto out;
1475                                 if((ret = mt6620_set_bits(0xF, 0x0,  0xFBFF)))
1476                                         goto out;
1477                         }
1478                         break;
1479
1480                 case Dynamic_Limiter:
1481                         if((ret = mt6620_write(FM_MAIN_PGSEL, 0x01)))
1482                                 goto out;
1483                         if(item_idx){
1484                                 if((ret = mt6620_set_bits(0xFA, 0x0, 0xFFF7)))
1485                                         goto out;
1486                         }else{
1487                                 if((ret = mt6620_set_bits(0xFA, 0x08, 0xFFF7)))
1488                                         goto out;
1489                         }
1490                         if((ret = mt6620_write(FM_MAIN_PGSEL, 0x0)))
1491                                 goto out;
1492                         break;
1493
1494                 case Softmute_Rate:
1495                         if((ret = mt6620_write(FM_MAIN_PGSEL, 0x01)))
1496                                 goto out;
1497                         if((ret = mt6620_set_bits(0xc8, item_value<<8, 0x80FF)))
1498                                 goto out;
1499                         if((ret = mt6620_write(FM_MAIN_PGSEL, 0x0)))
1500                                 goto out;
1501                         break;
1502
1503                 case AFC_Enable:
1504                         if (item_idx){
1505                                 if((ret = mt6620_set_bits(0x63, 0x0400, 0xFBFF)))
1506                                         goto out;
1507                         }else{
1508                                 if((ret = mt6620_set_bits(0x63, 0x0,    0xFBFF)))
1509                                         goto out;
1510                         }
1511                         break;
1512
1513 #if 0
1514                 case Softmute_Level:
1515                         mt6620_write(FM_MAIN_PGSEL, 0x01);
1516                         if(item_value > 0x24)
1517                                 item_value = 0x24;
1518                         mt6620_set_bits(0xD1, item_value, 0xFFC0);
1519                         mt6620_write(FM_MAIN_PGSEL, 0x0);
1520                         break;
1521 #endif
1522                 case Analog_Volume:
1523                         if((ret = mt6620_set_bits(0x9C, item_value<<8, 0xC0FF)))
1524                                 goto out;
1525                         break;
1526
1527                 default:
1528                         break;
1529         }
1530
1531 out:
1532         WCN_DBG(FM_NTC | CHIP,"-%s():[ret=%d]\n", __func__, ret);
1533         return ret;
1534 return fm_true;
1535 }
1536
1537 static const fm_u16 DesenseChMap[] = {
1538     0x0000, 0x0000, 0x0000, 0x0000, /* 7675~7600, 7755~7680, 7835~7760, 7915~7840 */
1539     0x0000, 0x0000, 0x0000, 0x0000, /* 7995~7920, 8075~8000, 8155~8080, 8235~8160 */
1540     0x0000, 0x0000, 0x0000, 0x0000, /* 8315~8240, 8395~8320, 8475~8400, 8555~8480 */
1541     0x0000, 0x0000, 0x0000, 0x0400, /* 8635~8560, 8715~8640, 8795~8720, 8875~8800 */
1542     0x0000, 0x0000, 0x0000, 0x0000, /* 8955~8880, 9035~8960, 9115~9040, 9195~9120 */
1543     0x00FC, 0x0000, 0x0000, 0x1C00, /* 9275~9200, 9355~9280, 9435~9360, 9515~9440 */
1544     0x0000, 0x0001, 0x0000, 0x0000, /* 9595~9520, 9675~9600, 9755~9680, 9835~9760 */
1545     0x0000, 0x7800, 0x0000, 0x0000, /* 9915~9840, 9995~9920, 10075~10000, 10155~10080 */
1546     0x0000, 0x0000, 0x0000, 0x0000, /* 10235~10160, 10315~10240, 10395~10320, 10475~10400 */
1547     0x0000, 0x0000, 0x0000, 0x0000, /* 10555~10480, 10635~10560, 10715~10640, 10795~10720 */
1548     0x0000                          /* 10875~10800 */
1549 };
1550 // return value: 0, not a de-sense channel; 1, this is a de-sense channel; else error no
1551 static fm_s32 mt6620_is_dese_chan(fm_u16 freq)
1552 {
1553         fm_u8 bDesenseCh = 0;
1554
1555     //caculate and applye compensation
1556     if (0 == fm_get_channel_space(freq))
1557     {
1558         freq *= 10;
1559     }
1560         WCN_DBG(FM_NTC | CHIP,"%s, freq=%d\n",__func__,freq);
1561     
1562         bDesenseCh = ((0x0001 << (((freq - 7600)%80)/5)) & DesenseChMap[((freq - 7600)/80)])>>(((freq - 7600)%80)/5); 
1563         WCN_DBG(FM_NTC | CHIP,"freq[%d] desense=[%d]\n",freq,bDesenseCh);
1564
1565     return bDesenseCh;
1566 }
1567
1568 /*  return value:
1569 1, is desense channel and rssi is less than threshold; 
1570 0, not desense channel or it is but rssi is more than threshold.*/
1571 static fm_s32 mt6620_desense_check(fm_u16 freq,fm_s32 rssi)
1572 {
1573         if(mt6620_is_dese_chan(freq))
1574         {
1575                 if(rssi<mt6620_fm_config.rx_cfg.desene_rssi_th)
1576                 {
1577                         return 1;
1578                 }
1579         }
1580     return 0;
1581 }
1582 static fm_s32 MT6620fm_low_power_wa_default(fm_s32 fmon)
1583 {
1584     return 0;
1585 }
1586
1587 fm_s32 MT6620fm_low_ops_register(struct fm_lowlevel_ops *ops)
1588 {
1589     fm_s32 ret = 0;
1590     //Basic functions.
1591
1592     FMR_ASSERT(ops);
1593     FMR_ASSERT(ops->cb.cur_freq_get);
1594     FMR_ASSERT(ops->cb.cur_freq_set);
1595     fm_cb_op = &ops->cb;
1596
1597     ops->bi.low_pwr_wa = MT6620fm_low_power_wa_default;
1598     ops->bi.pwron = mt6620_pwron;
1599     ops->bi.pwroff = mt6620_pwroff;
1600     ops->bi.msdelay = Delayms;
1601     ops->bi.usdelay = Delayus;
1602     ops->bi.read = mt6620_read;
1603     ops->bi.write = mt6620_write;
1604     ops->bi.setbits = mt6620_set_bits;
1605     ops->bi.chipid_get = mt6620_get_chipid;
1606     ops->bi.mute = mt6620_Mute;
1607     ops->bi.rampdown = mt6620_RampDown;
1608     ops->bi.pwrupseq = mt6620_PowerUp;
1609     ops->bi.pwrdownseq = mt6620_PowerDown;
1610     ops->bi.setfreq = mt6620_SetFreq;
1611     ops->bi.seek = mt6620_Seek;
1612     ops->bi.seekstop = mt6620_SeekStop;
1613     ops->bi.scan = mt6620_Scan;
1614     ops->bi.scanstop = mt6620_ScanStop;
1615     ops->bi.rssiget = mt6620_GetCurRSSI;
1616     ops->bi.volset = mt6620_SetVol;
1617     ops->bi.volget = mt6620_GetVol;
1618     ops->bi.dumpreg = mt6620_dump_reg;
1619     ops->bi.msget = mt6620_GetMonoStereo;
1620     ops->bi.msset = MT6620_SetMonoStereo;
1621     ops->bi.pamdget = mt6620_GetCurPamd;
1622     ops->bi.em = mt6620_em_test;
1623     ops->bi.anaswitch = mt6620_SetAntennaType;
1624     ops->bi.anaget = mt6620_GetAntennaType;
1625     ops->bi.caparray_get = mt6620_GetCapArray;
1626     ops->bi.i2s_set = mt6620_I2s_Setting;
1627     ops->bi.i2s_get = mt6620_i2s_info_get;
1628         ops->bi.is_dese_chan = mt6620_is_dese_chan;
1629         ops->bi.softmute_tune = mt6620_soft_mute_tune;
1630         ops->bi.desense_check = mt6620_desense_check;
1631         ops->bi.get_freq_cqi = mt6620_GetFreqCQI;
1632     ops->bi.hwinfo_get = mt6620_hw_info_get;
1633     ops->bi.fm_via_bt = MT6620_FMOverBT;
1634         /*****tx function****/
1635         ops->bi.tx_support = mt6620_Tx_Support;
1636         ops->bi.pwrupseq_tx = mt6620_PowerUpTx;
1637         ops->bi.tune_tx = MT6620_SetFreq_Tx;
1638         ops->bi.pwrdownseq_tx = mt6620_PowerDownTx;
1639         ops->bi.tx_scan = mt6620_TxScan;
1640     ops->ri.rds_tx = MT6620_Rds_Tx;
1641     ops->ri.rds_tx_enable = MT6620_Rds_Tx_Enable;
1642     ops->ri.rds_tx_disable = MT6620_Rds_Tx_Disable;
1643     ops->ri.rdstx_support = mt6620_rdsTx_Support;
1644     ops->bi.tx_pwr_ctrl = MT6620_TX_PWR_CTRL;
1645     ops->bi.rtc_drift_ctrl = MT6620_RTC_Drift_CTRL;
1646     ops->bi.tx_desense_wifi = MT6620_TX_DESENSE;
1647
1648         cmd_buf_lock = fm_lock_create("20_cmd");
1649         ret = fm_lock_get(cmd_buf_lock);
1650
1651         cmd_buf = fm_zalloc(TX_BUF_SIZE + 1);
1652
1653         if (!cmd_buf) {
1654                 WCN_DBG(FM_ALT | CHIP, "6620 fm lib alloc tx buf failed\n");
1655                 ret = -1;
1656         }
1657
1658 #if 0//def MTK_FM_50KHZ_SUPPORT
1659         cqi_fifo = fm_fifo_create("6620_cqi_fifo", sizeof(struct adapt_fm_cqi), 640);
1660         if (!cqi_fifo) {
1661                 WCN_DBG(FM_ALT | CHIP, "6620 fm lib create cqi fifo failed\n");
1662                 ret = -1;
1663         }
1664 #endif
1665
1666     return ret;
1667 }
1668
1669 fm_s32 MT6620fm_low_ops_unregister(struct fm_lowlevel_ops *ops)
1670 {
1671     fm_s32 ret = 0;
1672     //Basic functions.
1673 #if 0//def MTK_FM_50KHZ_SUPPORT
1674         fm_fifo_release(cqi_fifo);
1675 #endif
1676         
1677         if (cmd_buf) {
1678                 fm_free(cmd_buf);
1679                 cmd_buf = NULL;
1680         }
1681
1682         ret = fm_lock_put(cmd_buf_lock);
1683
1684     FMR_ASSERT(ops);
1685
1686     fm_memset(&ops->bi, 0, sizeof(struct fm_basic_interface));
1687     return ret;
1688 }
1689
1690
1691 /***********************************************************************
1692 *  Hi-Lo Side Injection
1693 *
1694 ***********************************************************************/
1695 fm_s32 MT6620_HL_Side_Adj(fm_u16 freq, fm_s32 *hl)
1696 {
1697     fm_s32 ret = 0;
1698     fm_s32 isHiSide= 0;
1699     fm_s32 tblsize = 0;
1700     fm_s32 indx = 0;
1701     fm_u16 tmp;
1702     static fm_u16 Hi_Channels[] = {7950, 8070, 8210, 10640};
1703
1704     if (0 == fm_get_channel_space(freq)) {
1705             freq *= 10;
1706     }
1707
1708     WCN_DBG(FM_DBG | CHIP,"+%s, [freq=%d]\n", __func__, (fm_s32)freq);
1709     
1710     *hl = 0;
1711     
1712     if(sizeof(Hi_Channels) == 0)
1713         goto out;
1714     
1715     tblsize = sizeof(Hi_Channels)/sizeof(Hi_Channels[0]);
1716     for(indx = 0; indx < tblsize; indx++){
1717         if(Hi_Channels[indx] == freq)
1718         {
1719             isHiSide = 1;
1720             *hl = 1;
1721             //goto set_HL;
1722             break;
1723         }     
1724     }
1725     
1726     if(isHiSide){
1727             //Set high-side injection (AFC)
1728             if((ret = mt6620_read(0x0F, &tmp)))
1729             goto out;
1730             if((ret = mt6620_write(0x0F, tmp |0x0400)))
1731             goto out;
1732             if((ret = mt6620_write(FM_MAIN_PGSEL, 0)))
1733             goto out;
1734             //Set high-side injection (DFE)
1735             if((ret = mt6620_read(0xCB, &tmp)))
1736             goto out;
1737             if((ret = mt6620_write(0xCB, tmp | 0x01)))
1738             goto out;
1739             //mt6620_write(0xCB, dataRead&0xFFFE);
1740     }else{
1741         //Set low-side injection (AFC)
1742         if((ret = mt6620_read(0x0F, &tmp)))
1743             goto out;
1744             if((ret = mt6620_write(0x0F, tmp&0xFBFF)))
1745             goto out;
1746             if((ret = mt6620_write(FM_MAIN_PGSEL, 0)))
1747             goto out;
1748             //Set low-side injection (DFE)
1749             if((ret = mt6620_read(0xCB, &tmp)))
1750             goto out;
1751             //mt6620_write(0xCB, dataRead | 0x01);
1752         if((ret = mt6620_write(0xCB, tmp&0xFFFE)))
1753             goto out;
1754     }
1755  out:   
1756     WCN_DBG(FM_NTC | CHIP,"-%s, [isHiSide=%d][ret=%d]\n", __func__, (fm_s32)isHiSide, ret);
1757     return ret;
1758 }
1759
1760 /***********************************************************************
1761 *  ADPLL Power On or Off
1762 *
1763 ***********************************************************************/
1764 fm_s32 MT6620_ADPLL_Power_OnOff(fm_s32 onoff, fm_s32 ADPLL_clk)
1765 {
1766     fm_s32 ret = 0;
1767
1768     
1769     switch(onoff){
1770         case FM_ADPLL_ON:
1771             if((ret = mt6620_write(0x25, 0x040F)))
1772                 goto out;
1773             //Remove the Reset_N
1774             if((ret = mt6620_write(0x20, 0x2720)))
1775                 goto out;
1776             // change DLF loop gain  
1777             // Set FMCR_DLF_GAIN_A = "9"
1778             // Set FMCR_DLF_GAIN_B = "9"
1779             if((ret = mt6620_write(0x22, 0x9980)))
1780                 goto out;
1781             //Configure initial I_CODE for calibration
1782             if((ret = mt6620_write(0x25, 0x080F)))
1783                 goto out;
1784             //Enable ADPLL DCO
1785             //Set FMCR_DCO_ EN = "1
1786             if(ADPLL_clk == FM_ADPLL_16M){
1787                 if((ret = mt6620_write(0x1E, 0x0A63)))
1788                     goto out;
1789                 // wait 5ms 
1790                 Delayms(5);
1791                 if((ret = mt6620_write(0x1E, 0x0A65)))
1792                     goto out;
1793                 // wait 5ms 
1794                 Delayms(5);
1795                 if((ret = mt6620_write(0x1E, 0x0A71)))
1796                     goto out;
1797             }else if(ADPLL_clk == FM_ADPLL_15M){
1798             if((ret = mt6620_write(0x1E, 0x0863)))
1799                 goto out;
1800             // wait 5ms 
1801             Delayms(5);
1802             if((ret = mt6620_write(0x1E, 0x0865)))
1803                 goto out;
1804             // wait 5ms 
1805             Delayms(5);
1806             if((ret = mt6620_write(0x1E, 0x0871)))
1807                 goto out;
1808             }else{
1809                 ret = -FM_EPARA;
1810                 goto out;
1811             }
1812             // wait 100ms 
1813             Delayms(100);
1814             if((ret = mt6620_write(0x2A, 0x1026)))
1815                 goto out;
1816             break;
1817             
1818         //ADPLL Power Off Sequence
1819         case FM_ADPLL_OFF:
1820             // Set rgfrf_top_ck = "0"
1821             if((ret = mt6620_set_bits(0x2A, 0, MASK(12))))//set 2A D12=0
1822                 goto out;
1823             // Set FMCR_OPEN_LOOP_EN = "0"
1824             // Set FMCR_PLL_EN = "0"
1825             // Set FMCR_DCO_EN = "0"
1826             if((ret = mt6620_set_bits(0x1E, 0, MASK(7)&MASK(4)&MASK(0))))//set 1E D7 D4 D0=0
1827                 goto out;
1828             // Set rgfrf_adpll_reset_n = "0"
1829             if((ret = mt6620_set_bits(0x20, 0, MASK(13))))//set 20 D13=0
1830                 goto out;
1831             // Set rgfrf_adpll_reset_n = "1"
1832             if((ret = mt6620_set_bits(0x20, BITn(13), MASK(13))))//set 20 D13=1
1833                 goto out;
1834             break;
1835         default:
1836             break;
1837     }
1838 out:
1839     return ret;
1840 }
1841
1842 /***********************************************************************
1843 *  Frequency Avoidance
1844 *
1845 ***********************************************************************/
1846 fm_s32 MT6620_ADPLL_Freq_Avoid(fm_u16 freq, fm_s32 *freqavoid)
1847 {
1848     fm_s32 ret = 0;
1849     fm_s32 ADPLL_clk = FM_ADPLL_15M;
1850     fm_u16 dataRead = 0;
1851     fm_u16 indx = 0;
1852     static fm_u16 Avoid_Channels[] ={ 
1853         7670, 7680, 7690, 7700, 8060, 8070, 8080, 8440, 8450, 8460, 8720, 8830, 8840, 9200,
1854         9210, 9220, 9230, 9360, 9490, 9600, 9610, 9980, 9990, 10000, 10130, 10360, 10370, 10380, 10740,
1855         10750, 10760, 10770
1856     };
1857
1858     if (0 == fm_get_channel_space(freq)) {
1859         freq *= 10;
1860     }
1861
1862     WCN_DBG(FM_DBG | CHIP,"+%s, [freq=%d]\n", __func__, (fm_s32)freq);
1863
1864     *freqavoid = 0;
1865     
1866     dataRead = sizeof(Avoid_Channels)/sizeof(Avoid_Channels[0]);
1867     indx = 0;
1868     while((indx < dataRead) && (ADPLL_clk != FM_ADPLL_16M)){
1869         if(Avoid_Channels[indx] == freq){
1870             ADPLL_clk = FM_ADPLL_16M;
1871             *freqavoid = 1;
1872         }
1873         indx++;
1874     }
1875     //isADPLL_16M = 1;
1876     if((ret = mt6620_read(0x1E, &dataRead)))
1877         goto out;
1878     if(((dataRead&BITn(9))&&(ADPLL_clk == FM_ADPLL_16M))||(!(dataRead&BITn(9))&&(ADPLL_clk == FM_ADPLL_15M)))//1EH, D9
1879         goto out; //we need not do freq avoid at these caes
1880
1881     if(ADPLL_clk == FM_ADPLL_16M){       
1882         //Set rgf_f16mode_en = X        
1883         if((ret = mt6620_set_bits(0x61, BITn(0), MASK(0))))//set 61H D0=1, 16.384MHZ
1884                 goto out;
1885     }else if(ADPLL_clk == FM_ADPLL_15M){
1886         //Set rgf_f16mode_en = X                
1887         if((ret = mt6620_set_bits(0x61, 0, MASK(0))))//set 61H D0=0, 15.36MHZ
1888                 goto out;
1889     }else{
1890         ret = -FM_EPARA;
1891         goto out;
1892     } 
1893     
1894     // Disable ADPLL
1895     ret = MT6620_ADPLL_Power_OnOff(FM_ADPLL_OFF, ADPLL_clk);
1896     if(ret){
1897         WCN_DBG(FM_NTC | CHIP,"%s, ADPLL OFF failed, [ret=%d]n", __func__, ret);
1898         goto out;
1899     }
1900     
1901     //Set FMCR_DCO_CK_SEL = ? (default = 0, 15.36)
1902     if(ADPLL_clk == FM_ADPLL_16M){              
1903         if((ret = mt6620_set_bits(0x1E, BITn(9), MASK(9))))//set 1EH D9=1, 16.384MHZ
1904                 goto out;
1905     }else if(ADPLL_clk == FM_ADPLL_15M){
1906         if((ret = mt6620_set_bits(0x1E, 0, MASK(9))))//set 1EH D9=0, 15.36MHZ
1907                 goto out;
1908     }else{
1909         ret = -FM_EPARA;
1910         goto out;
1911     }
1912     
1913     // Ensable ADPLL
1914     ret = MT6620_ADPLL_Power_OnOff(FM_ADPLL_ON, ADPLL_clk);
1915     if(ret){
1916         WCN_DBG(FM_NTC | CHIP,"%s, ADPLL ON failed, [ret=%d]\n", __func__, ret);
1917         goto out;
1918     }
1919     //Set rgfrf_cnt_resync_b = 0
1920     if((ret = mt6620_set_bits(0x2A, 0, MASK(1))))//set 2AH D1=0
1921         goto out;
1922     //Set rgfrf_cnt_resync_b = 1
1923     if((ret = mt6620_set_bits(0x2A, BITn(1), MASK(1))))//set 2AH D1=1
1924         goto out; 
1925 out:
1926     WCN_DBG(FM_NTC | CHIP,"-%s, [ADPLL_clk=%d][ret=%d]\n", __func__, (fm_s32)ADPLL_clk, ret);
1927     return ret;
1928 }
1929
1930 /***********************************************************************
1931 *  Frequency Avoidance
1932 *
1933 ***********************************************************************/
1934 fm_s32 MT6620_MCU_Freq_Avoid(fm_u16 freq, fm_s32 *freqavoid)
1935 {
1936     fm_s32 ret = 0;
1937     fm_s32 mcuDsense = FM_MCU_DESE_DISABLE;
1938     fm_u16 len = 0;
1939     fm_u16 indx = 0;
1940     static fm_u16 FreqList[] ={7800, 7940, 8320, 9260, 9600, 10400};
1941
1942     if (0 == fm_get_channel_space(freq)) {
1943         freq *= 10;
1944     }
1945
1946     WCN_DBG(FM_DBG | CHIP,"+%s, [freq=%d]\n", __func__, (fm_s32)freq);
1947
1948     *freqavoid = 0;
1949     
1950     len = sizeof(FreqList)/sizeof(FreqList[0]);
1951     indx = 0;
1952     while((indx < len) && (mcuDsense != FM_MCU_DESE_ENABLE)){
1953         if(FreqList[indx] == freq){
1954             mcuDsense = FM_MCU_DESE_ENABLE;
1955             *freqavoid = 1;
1956         }
1957         indx++;
1958     }
1959
1960         if(mcuDsense == FM_MCU_DESE_DISABLE){
1961                 if(mtk_wcn_wmt_dsns_ctrl(WMTDSNS_FM_DISABLE)){
1962                         ret = 0;
1963                 }else{
1964                         ret = -FM_ELINK;
1965                 }
1966         }else if(mcuDsense == FM_MCU_DESE_ENABLE){
1967                 if(mtk_wcn_wmt_dsns_ctrl(WMTDSNS_FM_ENABLE)){
1968                         ret = 0;
1969                 }else{
1970                         ret = -FM_ELINK;
1971                 }
1972         }else{
1973                 WCN_DBG(FM_ERR | CHIP,"para error!\n");
1974                 ret = -FM_EPARA;
1975         }
1976     
1977     WCN_DBG(FM_NTC | CHIP,"-%s, [mcuDsense=%d][ret=%d]\n", __func__, (fm_s32)mcuDsense, ret);
1978     return ret;
1979 }
1980
1981 /***********************************************************************
1982 *  TX PWR CTRL
1983 *
1984 ***********************************************************************/
1985 fm_s32 MT6620_TX_PWR_CTRL(fm_u16 freq, fm_s32 *ctr)
1986 {
1987     #define MT6620_TX_PWR_LEV_MAX 120
1988     #define MT6620_TX_PWR_LEV_MIN 85
1989     fm_s32 ret = 0;
1990     fm_s32 tmp = 0;
1991     fm_u16 reg = 0;
1992     fm_u16 coarse;
1993     fm_u16 fine;
1994     
1995     WCN_DBG(FM_DBG | CHIP,"+%s, [freq=%d]\n", __func__, (fm_s32)freq);
1996
1997     if(freq < FM_TX_PWR_CTRL_FREQ_THR){
1998         //Power setting - 1dB, 3C(HEX)=A9E9
1999         *ctr -= 1;
2000     }else{
2001         //Power setting -2 dB, 3C(HEX)=A8E9
2002         *ctr -= 2;
2003     }
2004     
2005     if(*ctr > MT6620_TX_PWR_LEV_MAX){
2006         *ctr = MT6620_TX_PWR_LEV_MAX;
2007     }else if(*ctr < MT6620_TX_PWR_LEV_MIN){
2008         *ctr = MT6620_TX_PWR_LEV_MIN;
2009     }
2010     fine = 43017 + ((1<<((*ctr-85)%6))-1)*32;
2011     WCN_DBG(FM_DBG | CHIP,"0x3C = 0x%04x \n", fine);
2012     coarse = 514 + ((1<<((*ctr-85)/6))-1)*4;
2013     WCN_DBG(FM_DBG | CHIP,"0x3D = 0x%04x \n", coarse);
2014     
2015     if((ret = mt6620_write(0x3C, fine)))
2016             goto out;
2017     if((ret = mt6620_write(0x3D, coarse)))
2018             goto out;
2019
2020     tmp = mtk_wcn_wmt_therm_ctrl(WMTTHERM_READ);
2021     if((ret = mt6620_read(0x9C, &reg)))
2022         goto out;
2023     reg &= 0xC0FF;
2024     if(tmp < FM_TX_PWR_CTRL_TMP_THR_DOWN){
2025         reg |= (0x1C << 8);  //9CH, D13~D8 = 1C
2026     }else if(tmp > FM_TX_PWR_CTRL_TMP_THR_UP){
2027         reg |= (0x33 << 8);  //9CH, D13~D8 ==33
2028     }else{
2029         reg |= (0x25 << 8);  //9CH, D13~D8 =25
2030     }
2031     if((ret = mt6620_write(0x9C, reg)))
2032         goto out;
2033
2034 out:
2035     WCN_DBG(FM_NTC | CHIP,"-%s, [temp=%d][ret=%d]\n", __func__, (fm_s32)tmp, ret);
2036     return ret;
2037 }
2038
2039 /***********************************************************************
2040 *  TX RTC PWR CTRL
2041 *
2042 ***********************************************************************/
2043 fm_s32 MT6620_RTC_Drift_CTRL(fm_u16 freq, fm_s32 *ctr)
2044 {
2045     fm_s32 ret = 0;
2046     fm_u16 reg = 0;
2047     fm_s32 chanel_resolution = 1;
2048     fm_s16 compensation_int16 = 0;
2049     fm_s32 tmp = 0;
2050     fm_s32 drift = *ctr;
2051     
2052     WCN_DBG(FM_DBG | CHIP,"+%s, [freq=%d]\n", __func__, (fm_s32)freq);
2053
2054     //turn off VCO tracking
2055     if((ret = mt6620_set_bits(0x48, 0, MASK(15))))//set 48 D15=0
2056         goto out;
2057     
2058     //get channel resolution
2059     if((ret = mt6620_read(0x46, &reg)))
2060         goto out;
2061     reg &= 0xC000;
2062     switch(reg >> 14){
2063         case 0:
2064             chanel_resolution = 1024;
2065             break;
2066         case 1:
2067             chanel_resolution = 512;
2068             break;
2069         case 2:
2070             chanel_resolution = 256;
2071             break;
2072         case 3:
2073             chanel_resolution = 128;
2074             break;
2075         default:
2076             WCN_DBG(FM_ERR | CHIP,"chanel_resolution error[%d]\n", (fm_s32)(reg >> 14));
2077             break;
2078     }
2079
2080     //caculate and applye compensation
2081     if (0 == fm_get_channel_space(freq)) {
2082         freq *= 10;
2083     }
2084     WCN_DBG(FM_DBG | CHIP,"[resolution=%d][freq=%d][drift=%d]\n", chanel_resolution, (fm_s32)(freq/100), (*ctr));
2085     tmp = (2*drift*(freq/100))/chanel_resolution;
2086     compensation_int16 = (fm_s16)tmp;
2087     if(compensation_int16 >= 511){
2088         compensation_int16 = 511;
2089     }else if(compensation_int16 <= -512){
2090         compensation_int16 = -512;
2091     }
2092     if((ret = mt6620_read(0x47, &reg)))
2093         goto out;
2094     reg &= 0x003F;
2095     reg |= (compensation_int16 << 6);
2096     if((ret = mt6620_write(0x47, reg)))
2097         goto out;
2098
2099     /*
2100     //turn on VCO tracking
2101     if((ret = mt6620_set_bits(0x48, BITn(15), MASK(15))))//set 48 D15=1
2102         goto out;
2103         */
2104 out:
2105     WCN_DBG(FM_NTC | CHIP,"-%s, [compensation=%d][ret=%d]\n", __func__, (fm_s32)(compensation_int16), ret);
2106     return ret;
2107 }
2108
2109 /***********************************************************************
2110 *  TX desense with WIFI/BT
2111 *
2112 ***********************************************************************/
2113 fm_s32 MT6620_TX_DESENSE(fm_u16 freq, fm_s32 *ctr)
2114 {
2115     fm_s32 ret = 0;
2116     fm_u16 dataRead = 0;
2117     fm_u16 tmp = 0;
2118     
2119     WCN_DBG(FM_DBG|CHIP,"+%s, [freq=%d]\n", __func__, (fm_s32)freq);
2120
2121     // enable FM TX VCO tracking
2122     if((ret = mt6620_read(0x29, &dataRead)))//read 29 
2123         goto out;
2124     WCN_DBG(FM_NTC | CHIP,"Before VCO On, [0x29=0x%04x]\n", dataRead);
2125     if((ret = mt6620_read(0x12, &dataRead)))//read 12 
2126         goto out;
2127     WCN_DBG(FM_NTC | CHIP,"Before VCO On, [0x12=0x%04x]\n", dataRead);
2128     
2129     if((ret = mt6620_set_bits(0x12, 0, MASK(15))))//set 12 D15=0
2130         goto out;
2131     if((ret = mt6620_set_bits(0x41, BITn(0), MASK(0))))//set 41 D0=1
2132         goto out;
2133     if((ret = mt6620_set_bits(0x48, BITn(15), MASK(15))))//set 48 D15=1
2134         goto out;
2135
2136     // wait 100ms (VCO tracking 100ms)
2137     if(*ctr > FM_TX_TRACKING_TIME_MAX){
2138         *ctr = FM_TX_TRACKING_TIME_MAX;
2139     }
2140     Delayms(*ctr);
2141
2142     // disable FM TX VCO tracking
2143     if((ret = mt6620_set_bits(0x28, BITn(2), MASK(2))))//set 28 D2=1
2144         goto out;
2145     if((ret = mt6620_read(0x29, &dataRead)))//read 29 D11~D0
2146         goto out;
2147     WCN_DBG(FM_NTC | CHIP,"Before VCO Off, [0x29=0x%04x]\n", dataRead);
2148     tmp = dataRead&0x0FFF; // Read 0x29 D11~D0
2149     if((ret = mt6620_read(0x12, &dataRead)))//read 12 
2150         goto out;
2151     //Set 0x12 D15 to 1, D11:D0 to read(0x29 D11~D0)
2152     dataRead &= 0xF000; 
2153     dataRead |= tmp;
2154     dataRead |= 1<<15;
2155     if((ret = mt6620_write(0x12, dataRead)))
2156         goto out;
2157     WCN_DBG(FM_NTC | CHIP,"Before VCO Off, [0x12=0x%04x]\n", dataRead);
2158     if((ret = mt6620_set_bits(0x48, 0, MASK(15))))//set 48 D15=0
2159         goto out;
2160     if((ret = mt6620_set_bits(0x41, 0, MASK(0))))//set 41 D0=0
2161         goto out;
2162     
2163 out:
2164     WCN_DBG(FM_DBG | CHIP,"-%s, [freq=%d][delay=%dms][ret=%d]\n", __func__, (fm_s32)freq, *ctr, ret);
2165     return ret;
2166 }
2167
2168 static fm_s32 MT6620_Rds_Tx_Enable(void)
2169 {
2170         mt6620_write(0x9F, 0x0000);
2171         mt6620_write(0xAB, 0x3872);
2172         mt6620_write(0xAC, 0x3B3A);
2173         mt6620_write(0xAD, 0x0113);
2174         mt6620_write(0xAE, 0x03B2);
2175         mt6620_write(0xAF, 0x0001);
2176         mt6620_write(0xB1, 0x63EB);
2177         mt6620_write(0xF4, 0x0020);
2178         mt6620_write(0xF5, 0x3222);
2179
2180     return 0;
2181 }
2182
2183 static fm_s32 MT6620_Rds_Tx_Disable(void)
2184 {
2185         mt6620_write(0x9F, 0x0000);
2186         mt6620_write(0xAB, 0x39B6);
2187         mt6620_write(0xAC, 0x3C3E);
2188         mt6620_write(0xAD, 0x0000);
2189         mt6620_write(0xAE, 0x03C2);
2190         mt6620_write(0xAF, 0x0001);
2191         mt6620_write(0xF4, 0x0020);
2192         mt6620_write(0xF5, 0xBF16);
2193         mt6620_write(0xB1, 0x623D);
2194
2195     return 0;
2196 }
2197
2198 static fm_s32 MT6620_Rds_Tx(fm_u16 pi, fm_u16 *ps, fm_u16 *other_rds, fm_u8 other_rds_cnt)
2199 {
2200     fm_s32 ret = 0;
2201     fm_u16 pkt_size = 0;
2202
2203         WCN_DBG(FM_NTC | RDSC, "+%s():PI=0x%04x, PS=0x%04x/0x%04x/0x%04x, other_rds_cnt=%d \n",__func__, pi, ps[0], ps[1], ps[2], other_rds_cnt);
2204     if (FM_LOCK(cmd_buf_lock)) 
2205                 return (-FM_ELOCK);
2206     pkt_size = mt6620_rds_tx(cmd_buf, TX_BUF_SIZE, pi, ps, other_rds, other_rds_cnt);
2207     ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_RDS_TX, SW_RETRY_CNT, RDS_TX_TIMEOUT, NULL);
2208     FM_UNLOCK(cmd_buf_lock);
2209         
2210     return ret;
2211 }
2212