Commit | Line | Data |
---|---|---|
6fa3eb70 S |
1 | /* mt6627_rds.c |
2 | * | |
3 | * (C) Copyright 2009 | |
4 | * MediaTek <www.MediaTek.com> | |
5 | * hongcheng <hongcheng.xia@MediaTek.com> | |
6 | * | |
7 | * mt6627 FM Radio Driver | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
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. | |
18 | * | |
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 | |
22 | */ | |
23 | #include "fm_typedef.h" | |
24 | #include "fm_dbg.h" | |
25 | #include "fm_err.h" | |
26 | #include "fm_interface.h" | |
27 | #include "fm_stdlib.h" | |
28 | #include "fm_rds.h" | |
29 | #include "mt6627_fm_reg.h" | |
30 | ||
31 | ||
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; | |
36 | ||
37 | static struct fm_callback *fm_cb; | |
38 | static struct fm_basic_interface *fm_bi; | |
39 | ||
40 | ||
41 | static fm_bool mt6627_RDS_support(void); | |
42 | static fm_s32 mt6627_RDS_enable(void); | |
43 | static fm_s32 mt6627_RDS_disable(void); | |
44 | static fm_u16 mt6627_RDS_Get_GoodBlock_Counter(void); | |
45 | static fm_u16 mt6627_RDS_Get_BadBlock_Counter(void); | |
46 | static fm_u8 mt6627_RDS_Get_BadBlock_Ratio(void); | |
47 | static fm_u32 mt6627_RDS_Get_BlerCheck_Interval(void); | |
48 | /* static void mt6627_RDS_GetData(fm_u16 *data, fm_u16 datalen); */ | |
49 | static void mt6627_RDS_Init_Data(rds_t *pstRDSData); | |
50 | ||
51 | ||
52 | ||
53 | static fm_bool mt6627_RDS_support(void) | |
54 | { | |
55 | return fm_true; | |
56 | } | |
57 | ||
58 | static fm_s32 mt6627_RDS_enable(void) | |
59 | { | |
60 | fm_s32 ret = 0; | |
61 | fm_u16 dataRead; | |
62 | ||
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)); | |
68 | ||
69 | return ret; | |
70 | } | |
71 | ||
72 | static fm_s32 mt6627_RDS_disable(void) | |
73 | { | |
74 | fm_s32 ret = 0; | |
75 | fm_u16 dataRead; | |
76 | ||
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)); | |
80 | ||
81 | return ret; | |
82 | } | |
83 | ||
84 | static fm_u16 mt6627_RDS_Get_GoodBlock_Counter(void) | |
85 | { | |
86 | fm_u16 tmp_reg; | |
87 | ||
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); | |
91 | ||
92 | return tmp_reg; | |
93 | } | |
94 | ||
95 | static fm_u16 mt6627_RDS_Get_BadBlock_Counter(void) | |
96 | { | |
97 | fm_u16 tmp_reg; | |
98 | ||
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); | |
102 | ||
103 | return tmp_reg; | |
104 | } | |
105 | ||
106 | static fm_u8 mt6627_RDS_Get_BadBlock_Ratio(void) | |
107 | { | |
108 | fm_u16 tmp_reg; | |
109 | fm_u16 gbc; | |
110 | fm_u16 bbc; | |
111 | ||
112 | gbc = mt6627_RDS_Get_GoodBlock_Counter(); | |
113 | bbc = mt6627_RDS_Get_BadBlock_Counter(); | |
114 | ||
115 | if ((gbc + bbc) > 0) { | |
116 | tmp_reg = (fm_u8) (bbc * 100 / (gbc + bbc)); | |
117 | } else { | |
118 | tmp_reg = 0; | |
119 | } | |
120 | ||
121 | BAD_BLK_RATIO = tmp_reg; | |
122 | WCN_DBG(FM_DBG | RDSC, "get badblock ratio:%d\n", (fm_s32) tmp_reg); | |
123 | ||
124 | return tmp_reg; | |
125 | } | |
126 | ||
127 | static fm_s32 mt6627_RDS_BlockCounter_Reset(void) | |
128 | { | |
129 | mt6627_RDS_disable(); | |
130 | mt6627_RDS_enable(); | |
131 | ||
132 | return 0; | |
133 | } | |
134 | ||
135 | static fm_u32 mt6627_RDS_Get_BlerCheck_Interval(void) | |
136 | { | |
137 | return gBLER_CHK_INTERVAL; | |
138 | } | |
139 | ||
140 | static fm_s32 mt6627_RDS_BlerCheck(rds_t *dst) | |
141 | { | |
142 | return 0; | |
143 | } | |
144 | ||
145 | #if 0 | |
146 | static void RDS_Recovery_Handler(void) | |
147 | { | |
148 | fm_u16 tempData = 0; | |
149 | ||
150 | do { | |
151 | fm_bi->read(FM_RDS_DATA_REG, &tempData); | |
152 | fm_bi->read(FM_RDS_POINTER, &tempData); | |
153 | } while (tempData & 0x3); | |
154 | } | |
155 | #endif | |
156 | ||
157 | #if 0 | |
158 | static void mt6627_RDS_GetData(fm_u16 *data, fm_u16 datalen) | |
159 | { | |
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 | |
165 | ||
166 | fm_u16 CRC = 0, i = 0, RDS_adj = 0, RDSDataCount = 0, FM_WARorrCnt = 0; | |
167 | fm_u16 temp = 0, OutputPofm_s32 = 0; | |
168 | ||
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); | |
172 | ||
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]); | |
180 | ||
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]); | |
187 | ||
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]); | |
194 | ||
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]); | |
201 | ||
202 | data[4] = (CRC | RDS_adj | RDSDataCount); | |
203 | data[5] = FM_WARorrCnt; | |
204 | ||
205 | fm_bi->read(FM_RDS_PWDI, &data[6]); | |
206 | fm_bi->read(FM_RDS_PWDQ, &data[7]); | |
207 | ||
208 | fm_bi->read(FM_RDS_POINTER, &OutputPofm_s32); | |
209 | ||
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(); | |
213 | } | |
214 | ||
215 | } else { | |
216 | for (; i < 8; i++) | |
217 | data[i] = 0; | |
218 | } | |
219 | } | |
220 | #endif | |
221 | ||
222 | static void mt6627_RDS_Init_Data(rds_t *pstRDSData) | |
223 | { | |
224 | fm_memset(pstRDSData, 0, sizeof(rds_t)); | |
225 | bRDS_FirstIn = fm_true; | |
226 | ||
227 | pstRDSData->event_status = 0x0000; | |
228 | fm_memset(pstRDSData->RT_Data.TextData, 0x20, sizeof(pstRDSData->RT_Data.TextData)); | |
229 | fm_memset(pstRDSData->PS_Data.PS, '\0', sizeof(pstRDSData->PS_Data.PS)); | |
230 | fm_memset(pstRDSData->PS_ON, 0x20, sizeof(pstRDSData->PS_ON)); | |
231 | } | |
232 | ||
233 | fm_bool mt6627_RDS_OnOff(rds_t *dst, fm_bool bFlag) | |
234 | { | |
235 | if (mt6627_RDS_support() == fm_false) { | |
236 | WCN_DBG(FM_ALT | RDSC, "mt6627_RDS_OnOff failed, RDS not support\n"); | |
237 | return fm_false; | |
238 | } | |
239 | ||
240 | if (bFlag) { | |
241 | mt6627_RDS_Init_Data(dst); | |
242 | mt6627_RDS_enable(); | |
243 | } else { | |
244 | mt6627_RDS_Init_Data(dst); | |
245 | mt6627_RDS_disable(); | |
246 | } | |
247 | ||
248 | return fm_true; | |
249 | } | |
250 | ||
251 | DEFINE_RDSLOG(mt6627_rds_log); | |
252 | ||
253 | /* mt6627_RDS_Efm_s32_Handler - response FM RDS interrupt | |
254 | * @fm - main data structure of FM driver | |
255 | * This function first get RDS raw data, then call RDS spec parser | |
256 | */ | |
257 | static fm_s32 mt6627_rds_parser(rds_t *rds_dst, struct rds_rx_t *rds_raw, fm_s32 rds_size, | |
258 | fm_u16(*getfreq) (void)) | |
259 | { | |
260 | mt6627_rds_log.log_in(&mt6627_rds_log, rds_raw, rds_size); | |
261 | return rds_parser(rds_dst, rds_raw, rds_size, getfreq); | |
262 | } | |
263 | ||
264 | static fm_s32 mt6627_rds_log_get(struct rds_rx_t *dst, fm_s32 *dst_len) | |
265 | { | |
266 | return mt6627_rds_log.log_out(&mt6627_rds_log, dst, dst_len); | |
267 | } | |
268 | ||
269 | static fm_s32 mt6627_rds_gc_get(struct rds_group_cnt_t *dst, rds_t *rdsp) | |
270 | { | |
271 | return rds_grp_counter_get(dst, &rdsp->gc); | |
272 | } | |
273 | ||
274 | static fm_s32 mt6627_rds_gc_reset(rds_t *rdsp) | |
275 | { | |
276 | return rds_grp_counter_reset(&rdsp->gc); | |
277 | } | |
278 | ||
279 | fm_s32 MT6627fm_rds_ops_register(struct fm_lowlevel_ops *ops) | |
280 | { | |
281 | fm_s32 ret = 0; | |
282 | ||
283 | FMR_ASSERT(ops); | |
284 | FMR_ASSERT(ops->bi.write); | |
285 | FMR_ASSERT(ops->bi.read); | |
286 | FMR_ASSERT(ops->bi.setbits); | |
287 | FMR_ASSERT(ops->bi.usdelay); | |
288 | fm_bi = &ops->bi; | |
289 | ||
290 | FMR_ASSERT(ops->cb.cur_freq_get); | |
291 | FMR_ASSERT(ops->cb.cur_freq_set); | |
292 | fm_cb = &ops->cb; | |
293 | ||
294 | ops->ri.rds_blercheck = mt6627_RDS_BlerCheck; | |
295 | ops->ri.rds_onoff = mt6627_RDS_OnOff; | |
296 | ops->ri.rds_parser = mt6627_rds_parser; | |
297 | ops->ri.rds_gbc_get = mt6627_RDS_Get_GoodBlock_Counter; | |
298 | ops->ri.rds_bbc_get = mt6627_RDS_Get_BadBlock_Counter; | |
299 | ops->ri.rds_bbr_get = mt6627_RDS_Get_BadBlock_Ratio; | |
300 | ops->ri.rds_bc_reset = mt6627_RDS_BlockCounter_Reset; | |
301 | ops->ri.rds_bci_get = mt6627_RDS_Get_BlerCheck_Interval; | |
302 | ops->ri.rds_log_get = mt6627_rds_log_get; | |
303 | ops->ri.rds_gc_get = mt6627_rds_gc_get; | |
304 | ops->ri.rds_gc_reset = mt6627_rds_gc_reset; | |
305 | return ret; | |
306 | } | |
307 | ||
308 | fm_s32 MT6627fm_rds_ops_unregister(struct fm_lowlevel_ops *ops) | |
309 | { | |
310 | fm_s32 ret = 0; | |
311 | ||
312 | FMR_ASSERT(ops); | |
313 | ||
314 | fm_bi = NULL; | |
315 | fm_memset(&ops->ri, 0, sizeof(struct fm_rds_interface)); | |
316 | return ret; | |
317 | } |