4 * MediaTek <www.MediaTek.com>
5 * hongcheng <hongcheng.xia@MediaTek.com>
7 * mt6630 FM Radio Driver
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "fm_typedef.h"
26 #include "fm_interface.h"
27 #include "fm_stdlib.h"
29 #include "mt6630_fm_reg.h"
32 static fm_bool bRDS_FirstIn
= fm_false
;
33 static fm_u32 gBLER_CHK_INTERVAL
= 5000;
34 static fm_u16 GOOD_BLK_CNT
= 0, BAD_BLK_CNT
;
35 static fm_u8 BAD_BLK_RATIO
;
37 static struct fm_callback
*fm_cb
;
38 static struct fm_basic_interface
*fm_bi
;
41 static fm_bool
mt6630_RDS_support(void);
42 static fm_s32
mt6630_RDS_enable(void);
43 static fm_s32
mt6630_RDS_disable(void);
44 static fm_u16
mt6630_RDS_Get_GoodBlock_Counter(void);
45 static fm_u16
mt6630_RDS_Get_BadBlock_Counter(void);
46 static fm_u8
mt6630_RDS_Get_BadBlock_Ratio(void);
47 static fm_u32
mt6630_RDS_Get_BlerCheck_Interval(void);
48 /* static void mt6630_RDS_GetData(fm_u16 *data, fm_u16 datalen); */
49 static void mt6630_RDS_Init_Data(rds_t
*pstRDSData
);
53 static fm_bool
mt6630_RDS_support(void)
58 static fm_s32
mt6630_RDS_enable(void)
63 WCN_DBG(FM_DBG
| RDSC
, "rds enable\n");
64 /* ret = fm_bi->read(FM_RDS_CFG0, &dataRead); */
65 ret
= fm_bi
->write(FM_RDS_CFG0
, 6); /* set buf_start_th */
66 ret
= fm_bi
->read(FM_MAIN_CTRL
, &dataRead
);
67 ret
= fm_bi
->write(FM_MAIN_CTRL
, dataRead
| (RDS_MASK
));
72 static fm_s32
mt6630_RDS_disable(void)
77 WCN_DBG(FM_DBG
| RDSC
, "rds disable\n");
78 ret
= fm_bi
->read(FM_MAIN_CTRL
, &dataRead
);
79 ret
= fm_bi
->write(FM_MAIN_CTRL
, dataRead
& (~RDS_MASK
));
84 static fm_u16
mt6630_RDS_Get_GoodBlock_Counter(void)
88 fm_bi
->read(FM_RDS_GOODBK_CNT
, &tmp_reg
);
89 GOOD_BLK_CNT
= tmp_reg
;
90 WCN_DBG(FM_DBG
| RDSC
, "get good block cnt:%d\n", (fm_s32
) tmp_reg
);
95 static fm_u16
mt6630_RDS_Get_BadBlock_Counter(void)
99 fm_bi
->read(FM_RDS_BADBK_CNT
, &tmp_reg
);
100 BAD_BLK_CNT
= tmp_reg
;
101 WCN_DBG(FM_DBG
| RDSC
, "get bad block cnt:%d\n", (fm_s32
) tmp_reg
);
106 static fm_u8
mt6630_RDS_Get_BadBlock_Ratio(void)
112 gbc
= mt6630_RDS_Get_GoodBlock_Counter();
113 bbc
= mt6630_RDS_Get_BadBlock_Counter();
115 if ((gbc
+ bbc
) > 0) {
116 tmp_reg
= (fm_u8
) (bbc
* 100 / (gbc
+ bbc
));
121 BAD_BLK_RATIO
= tmp_reg
;
122 WCN_DBG(FM_DBG
| RDSC
, "get badblock ratio:%d\n", (fm_s32
) tmp_reg
);
127 static fm_s32
mt6630_RDS_BlockCounter_Reset(void)
129 mt6630_RDS_disable();
135 static fm_u32
mt6630_RDS_Get_BlerCheck_Interval(void)
137 return gBLER_CHK_INTERVAL
;
140 static fm_s32
mt6630_RDS_BlerCheck(rds_t
*dst
)
146 static void RDS_Recovery_Handler(void)
151 fm_bi
->read(FM_RDS_DATA_REG
, &tempData
);
152 fm_bi
->read(FM_RDS_POINTER
, &tempData
);
153 } while (tempData
& 0x3);
158 static void mt6630_RDS_GetData(fm_u16
*data
, fm_u16 datalen
)
160 #define RDS_GROUP_DIFF_OFS 0x007C
161 #define RDS_FIFO_DIFF 0x007F
162 #define RDS_CRC_BLK_ADJ 0x0020
163 #define RDS_CRC_CORR_CNT 0x001E
164 #define RDS_CRC_INFO 0x0001
166 fm_u16 CRC
= 0, i
= 0, RDS_adj
= 0, RDSDataCount
= 0, FM_WARorrCnt
= 0;
167 fm_u16 temp
= 0, OutputPofm_s32
= 0;
169 WCN_DBG(FM_DBG
| RDSC
, "get data\n");
170 fm_bi
->read(FM_RDS_FIFO_STATUS0
, &temp
);
171 RDSDataCount
= ((RDS_GROUP_DIFF_OFS
& temp
) << 2);
173 if ((temp
& RDS_FIFO_DIFF
) >= 4) {
174 /* block A data and info handling */
175 fm_bi
->read(FM_RDS_INFO
, &temp
);
176 RDS_adj
|= (temp
& RDS_CRC_BLK_ADJ
) << 10;
177 CRC
|= (temp
& RDS_CRC_INFO
) << 3;
178 FM_WARorrCnt
|= ((temp
& RDS_CRC_CORR_CNT
) << 11);
179 fm_bi
->read(FM_RDS_DATA_REG
, &data
[0]);
181 /* block B data and info handling */
182 fm_bi
->read(FM_RDS_INFO
, &temp
);
183 RDS_adj
|= (temp
& RDS_CRC_BLK_ADJ
) << 9;
184 CRC
|= (temp
& RDS_CRC_INFO
) << 2;
185 FM_WARorrCnt
|= ((temp
& RDS_CRC_CORR_CNT
) << 7);
186 fm_bi
->read(FM_RDS_DATA_REG
, &data
[1]);
188 /* block C data and info handling */
189 fm_bi
->read(FM_RDS_INFO
, &temp
);
190 RDS_adj
|= (temp
& RDS_CRC_BLK_ADJ
) << 8;
191 CRC
|= (temp
& RDS_CRC_INFO
) << 1;
192 FM_WARorrCnt
|= ((temp
& RDS_CRC_CORR_CNT
) << 3);
193 fm_bi
->read(FM_RDS_DATA_REG
, &data
[2]);
195 /* block D data and info handling */
196 fm_bi
->read(FM_RDS_INFO
, &temp
);
197 RDS_adj
|= (temp
& RDS_CRC_BLK_ADJ
) << 7;
198 CRC
|= (temp
& RDS_CRC_INFO
);
199 FM_WARorrCnt
|= ((temp
& RDS_CRC_CORR_CNT
) >> 1);
200 fm_bi
->read(FM_RDS_DATA_REG
, &data
[3]);
202 data
[4] = (CRC
| RDS_adj
| RDSDataCount
);
203 data
[5] = FM_WARorrCnt
;
205 fm_bi
->read(FM_RDS_PWDI
, &data
[6]);
206 fm_bi
->read(FM_RDS_PWDQ
, &data
[7]);
208 fm_bi
->read(FM_RDS_POINTER
, &OutputPofm_s32
);
210 /* Go fm_s32o RDS recovery handler while RDS output pofm_s32 doesn't align to 4 in numeric */
211 if (OutputPofm_s32
& 0x3) {
212 RDS_Recovery_Handler();
222 static void mt6630_RDS_Init_Data(rds_t
*pstRDSData
)
224 fm_memset(pstRDSData
, 0, sizeof(rds_t
));
225 bRDS_FirstIn
= fm_true
;
227 fm_memset(pstRDSData
->RT_Data
.TextData
, 0x20, sizeof(pstRDSData
->RT_Data
.TextData
));
228 fm_memset(pstRDSData
->PS_Data
.PS
, '\0', sizeof(pstRDSData
->PS_Data
.PS
));
229 fm_memset(pstRDSData
->PS_ON
, 0x20, sizeof(pstRDSData
->PS_ON
));
232 fm_bool
mt6630_RDS_OnOff(rds_t
*dst
, fm_bool bFlag
)
234 if (mt6630_RDS_support() == fm_false
) {
235 WCN_DBG(FM_ALT
| RDSC
, "mt6630_RDS_OnOff failed, RDS not support\n");
240 mt6630_RDS_Init_Data(dst
);
243 mt6630_RDS_disable();
249 DEFINE_RDSLOG(mt6630_rds_log
);
251 /* mt6630_RDS_Efm_s32_Handler - response FM RDS interrupt
252 * @fm - main data structure of FM driver
253 * This function first get RDS raw data, then call RDS spec parser
255 static fm_s32
mt6630_rds_parser(rds_t
*rds_dst
, struct rds_rx_t
*rds_raw
, fm_s32 rds_size
,
256 fm_u16(*getfreq
) (void))
258 mt6630_rds_log
.log_in(&mt6630_rds_log
, rds_raw
, rds_size
);
259 return rds_parser(rds_dst
, rds_raw
, rds_size
, getfreq
);
262 static fm_s32
mt6630_rds_log_get(struct rds_rx_t
*dst
, fm_s32
*dst_len
)
264 return mt6630_rds_log
.log_out(&mt6630_rds_log
, dst
, dst_len
);
267 static fm_s32
mt6630_rds_gc_get(struct rds_group_cnt_t
*dst
, rds_t
*rdsp
)
269 return rds_grp_counter_get(dst
, &rdsp
->gc
);
272 static fm_s32
mt6630_rds_gc_reset(rds_t
*rdsp
)
274 return rds_grp_counter_reset(&rdsp
->gc
);
277 fm_s32
MT6630fm_rds_ops_register(struct fm_lowlevel_ops
*ops
)
282 FMR_ASSERT(ops
->bi
.write
);
283 FMR_ASSERT(ops
->bi
.read
);
284 FMR_ASSERT(ops
->bi
.setbits
);
285 FMR_ASSERT(ops
->bi
.usdelay
);
288 FMR_ASSERT(ops
->cb
.cur_freq_get
);
289 FMR_ASSERT(ops
->cb
.cur_freq_set
);
292 ops
->ri
.rds_blercheck
= mt6630_RDS_BlerCheck
;
293 ops
->ri
.rds_onoff
= mt6630_RDS_OnOff
;
294 ops
->ri
.rds_parser
= mt6630_rds_parser
;
295 ops
->ri
.rds_gbc_get
= mt6630_RDS_Get_GoodBlock_Counter
;
296 ops
->ri
.rds_bbc_get
= mt6630_RDS_Get_BadBlock_Counter
;
297 ops
->ri
.rds_bbr_get
= mt6630_RDS_Get_BadBlock_Ratio
;
298 ops
->ri
.rds_bc_reset
= mt6630_RDS_BlockCounter_Reset
;
299 ops
->ri
.rds_bci_get
= mt6630_RDS_Get_BlerCheck_Interval
;
300 ops
->ri
.rds_log_get
= mt6630_rds_log_get
;
301 ops
->ri
.rds_gc_get
= mt6630_rds_gc_get
;
302 ops
->ri
.rds_gc_reset
= mt6630_rds_gc_reset
;
306 fm_s32
MT6630fm_rds_ops_unregister(struct fm_lowlevel_ops
*ops
)
313 fm_memset(&ops
->ri
, 0, sizeof(struct fm_rds_interface
));