MT6620: add the new driver JB2 V1.0
[firefly-linux-kernel-4.4.55.git] / drivers / mtk_wcn_combo / drv_fm / mt6628 / pub / mt6628_fm_link.c
1 /* mt6628_fm_link.c
2  *
3  * (C) Copyright 2009
4  * MediaTek <www.MediaTek.com>
5  * Hongcheng <hongcheng.xia@MediaTek.com>
6  *
7  * MT6628 FM Radio Driver -- setup data link
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  #if 0
24 #include <linux/slab.h>
25 #include <linux/interrupt.h>
26
27 #include "stp_exp.h"
28 #include "wmt_exp.h"
29
30 #include "fm_typedef.h"
31 #include "fm_dbg.h"
32 #include "fm_err.h"
33 #include "fm_stdlib.h"
34
35 #include "mt6628_fm.h"
36 #include "mt6628_fm_link.h"
37
38 static struct fm_link_event *link_event;
39
40 static struct fm_trace_fifo_t *cmd_fifo;
41
42 static struct fm_trace_fifo_t *evt_fifo;
43     
44 static fm_s32 (*reset)(fm_s32 sta) = NULL;
45
46 static void mt6628_fm_wholechip_rst_cb(ENUM_WMTDRV_TYPE_T src,
47                                 ENUM_WMTDRV_TYPE_T dst,
48                                 ENUM_WMTMSG_TYPE_T type,
49                                 void *buf,
50                                 unsigned int sz)
51 {
52     //To handle reset procedure please
53     ENUM_WMTRSTMSG_TYPE_T rst_msg;
54     
55     if (sz <= sizeof(ENUM_WMTRSTMSG_TYPE_T)) {
56         memcpy((char *)&rst_msg, (char *)buf, sz);
57         WCN_DBG(FM_WAR | LINK, "[src=%d], [dst=%d], [type=%d], [buf=0x%x], [sz=%d], [max=%d]\n", src, dst, type, rst_msg, sz, WMTRSTMSG_RESET_MAX);
58
59         if ((src == WMTDRV_TYPE_WMT) && (dst == WMTDRV_TYPE_FM) && (type == WMTMSG_TYPE_RESET)) {
60             if (rst_msg == WMTRSTMSG_RESET_START) {
61                 WCN_DBG(FM_WAR | LINK, "FM restart start!\n");
62                 if (reset) {
63                     reset(1);
64                 }
65                 
66             } else if (rst_msg == WMTRSTMSG_RESET_END) {
67                 WCN_DBG(FM_WAR | LINK, "FM restart end!\n");
68                 if (reset) {
69                     reset(0);
70                 }
71             }
72         }
73     } else {
74         /*message format invalid*/
75         WCN_DBG(FM_WAR | LINK, "message format invalid!\n");
76     }
77 }
78
79     
80 fm_s32 fm_link_setup(void* data)
81 {
82     fm_s32 ret = 0;
83     
84     if (!(link_event = fm_zalloc(sizeof(struct fm_link_event)))) {
85         WCN_DBG(FM_ALT | LINK, "fm_zalloc(fm_link_event) -ENOMEM\n");
86         return -1;
87     }
88
89     link_event->ln_event = fm_flag_event_create("ln_evt");
90
91     if (!link_event->ln_event) {
92         WCN_DBG(FM_ALT | LINK, "create mt6628_ln_event failed\n");
93         fm_free(link_event);
94         return -1;
95     }
96
97     fm_flag_event_get(link_event->ln_event);
98
99
100     WCN_DBG(FM_NTC | LINK, "fm link setup\n");
101
102     cmd_fifo = fm_trace_fifo_create("cmd_fifo");
103     if (!cmd_fifo) {
104         WCN_DBG(FM_ALT | LINK, "create cmd_fifo failed\n");
105         ret = -1;
106         goto failed;
107     }
108     
109     evt_fifo = fm_trace_fifo_create("evt_fifo");
110     if (!evt_fifo) {
111         WCN_DBG(FM_ALT | LINK, "create evt_fifo failed\n");
112         ret = -1;
113         goto failed;
114     }
115     
116     reset = data; // get whole chip reset cb
117     mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_FM, mt6628_fm_wholechip_rst_cb);
118     return 0;
119     
120 failed:
121     fm_trace_fifo_release(evt_fifo);
122     fm_trace_fifo_release(cmd_fifo);
123     fm_flag_event_put(link_event->ln_event);
124     if (link_event) {
125         fm_free(link_event);
126     }
127     
128     return ret;
129 }
130
131 fm_s32 fm_link_release(void)
132 {
133
134     fm_trace_fifo_release(evt_fifo);
135     fm_trace_fifo_release(cmd_fifo);
136     fm_flag_event_put(link_event->ln_event);
137     if (link_event) {
138         fm_free(link_event);
139     }
140
141     WCN_DBG(FM_NTC | LINK, "fm link release\n");
142     return 0;
143 }
144
145 /*
146  * fm_ctrl_rx
147  * the low level func to read a rigister
148  * @addr - rigister address
149  * @val - the pointer of target buf
150  * If success, return 0; else error code
151  */
152 fm_s32 fm_ctrl_rx(fm_u8 addr, fm_u16 *val)
153 {
154     return 0;
155 }
156
157 /*
158  * fm_ctrl_tx
159  * the low level func to write a rigister
160  * @addr - rigister address
161  * @val - value will be writed in the rigister
162  * If success, return 0; else error code
163  */
164 fm_s32 fm_ctrl_tx(fm_u8 addr, fm_u16 val)
165 {
166     return 0;
167 }
168
169 /*
170  * fm_cmd_tx() - send cmd to FM firmware and wait event
171  * @buf - send buffer
172  * @len - the length of cmd
173  * @mask - the event flag mask
174  * @    cnt - the retry conter
175  * @timeout - timeout per cmd
176  * Return 0, if success; error code, if failed
177  */
178 fm_s32 fm_cmd_tx(fm_u8* buf, fm_u16 len, fm_s32 mask, fm_s32 cnt, fm_s32 timeout, fm_s32(*callback)(struct fm_res_ctx* result))
179 {
180     fm_s32 ret_time = 0;
181     struct task_struct *task = current;
182     struct fm_trace_t trace;
183
184     if ((NULL == buf) || (len < 0) || (0 == mask)
185             || (cnt > SW_RETRY_CNT_MAX) || (timeout > SW_WAIT_TIMEOUT_MAX)) {
186         WCN_DBG(FM_ERR | LINK, "cmd tx, invalid para\n");
187         return -FM_EPARA;
188     }
189
190     FM_EVENT_CLR(link_event->ln_event, mask);
191     
192 #ifdef FM_TRACE_ENABLE
193     trace.type = buf[0];
194     trace.opcode = buf[1];
195     trace.len = len - 4;
196     trace.tid = (fm_s32)task->pid;
197     fm_memset(trace.pkt, 0, FM_TRACE_PKT_SIZE);
198     fm_memcpy(trace.pkt, &buf[4], (trace.len > FM_TRACE_PKT_SIZE) ? FM_TRACE_PKT_SIZE : trace.len);
199 #endif
200
201 sw_retry:
202
203 #ifdef FM_TRACE_ENABLE
204     if (fm_true == FM_TRACE_FULL(cmd_fifo)) {
205         FM_TRACE_OUT(cmd_fifo, NULL);
206     }
207     FM_TRACE_IN(cmd_fifo, &trace);
208 #endif
209
210     //send cmd to FM firmware
211     if (mtk_wcn_stp_send_data(buf, len, FM_TASK_INDX) == 0) {
212         WCN_DBG(FM_EMG | LINK, "send data over stp failed\n");
213         return -FM_ELINK;
214     }
215
216     //wait the response form FM firmware
217     ret_time = FM_EVENT_WAIT_TIMEOUT(link_event->ln_event, mask, timeout);
218
219     if (!ret_time) {
220         if (0 < cnt--) {
221             WCN_DBG(FM_WAR | LINK, "wait even timeout, [retry_cnt=%d], pid=%d\n", cnt, task->pid);
222             fm_print_cmd_fifo();
223             fm_print_evt_fifo();
224             return -FM_EFW;
225             goto sw_retry; //retry if timeout and retry cnt > 0
226         } else {
227             WCN_DBG(FM_ALT | LINK, "fatal error, SW retry failed, reset HW\n");
228             return -FM_EFW;
229         }
230     }
231
232     FM_EVENT_CLR(link_event->ln_event, mask);
233
234     if (callback) {
235         callback(&link_event->result);
236     }
237
238     return 0;
239 }
240
241 fm_s32 fm_event_parser(fm_s32(*rds_parser)(struct rds_rx_t*, fm_s32))
242 {
243     fm_s32 len;
244     fm_s32 i = 0;
245     fm_u8 opcode = 0;
246     fm_u16 length = 0;
247     fm_u8 ch;
248     fm_u8 rx_buf[RX_BUF_SIZE + 10] = {0}; //the 10 bytes are protect gaps
249     static volatile fm_task_parser_state state = FM_TASK_RX_PARSER_PKT_TYPE;
250     struct fm_trace_t trace;
251     struct task_struct *task = current;
252
253     len = mtk_wcn_stp_receive_data(rx_buf, RX_BUF_SIZE, FM_TASK_INDX);
254     WCN_DBG(FM_DBG | LINK, "[len=%d],[CMD=0x%02x 0x%02x 0x%02x 0x%02x]\n", len, rx_buf[0], rx_buf[1], rx_buf[2], rx_buf[3]);
255
256     while (i < len) {
257         ch = rx_buf[i];
258
259         switch (state) {
260         case FM_TASK_RX_PARSER_PKT_TYPE:
261
262             if (ch == FM_TASK_EVENT_PKT_TYPE) {
263                 if ((i + 5) < RX_BUF_SIZE) {
264                     WCN_DBG(FM_DBG | LINK, "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x \n", rx_buf[i], rx_buf[i+1], rx_buf[i+2], rx_buf[i+3], rx_buf[i+4], rx_buf[i+5]);
265                 } else {
266                     WCN_DBG(FM_DBG | LINK, "0x%02x 0x%02x\n", rx_buf[i], rx_buf[i+1]);
267                 }
268
269                 state = FM_TASK_RX_PARSER_OPCODE;
270             } else {
271                 WCN_DBG(FM_ALT | LINK, "event pkt type error (rx_buf[%d] = 0x%02x)\n", i, ch);
272             }
273
274             i++;
275             break;
276
277         case FM_TASK_RX_PARSER_OPCODE:
278             i++;
279             opcode = ch;
280             state = FM_TASK_RX_PARSER_PKT_LEN_1;
281             break;
282
283         case FM_TASK_RX_PARSER_PKT_LEN_1:
284             i++;
285             length = ch;
286             state = FM_TASK_RX_PARSER_PKT_LEN_2;
287             break;
288
289         case FM_TASK_RX_PARSER_PKT_LEN_2:
290             i++;
291             length |= (fm_u16)(ch << 0x8);
292
293 #ifdef FM_TRACE_ENABLE
294             trace.type = FM_TASK_EVENT_PKT_TYPE;
295             trace.opcode = opcode;
296             trace.len = length;
297             trace.tid = (fm_s32)task->pid;
298             fm_memset(trace.pkt, 0, FM_TRACE_PKT_SIZE);
299             fm_memcpy(trace.pkt, &rx_buf[i], (length > FM_TRACE_PKT_SIZE) ? FM_TRACE_PKT_SIZE : length);
300
301             if (fm_true == FM_TRACE_FULL(cmd_fifo)) {
302                 FM_TRACE_OUT(cmd_fifo, NULL);
303             }
304             FM_TRACE_IN(cmd_fifo, &trace);
305 #endif
306             if (length > 0) {
307                 state = FM_TASK_RX_PARSER_PKT_PAYLOAD;
308             } else {
309                 state = FM_TASK_RX_PARSER_PKT_TYPE;
310                 FM_EVENT_SEND(link_event->ln_event, (1 << opcode));
311             }
312
313             break;
314
315         case FM_TASK_RX_PARSER_PKT_PAYLOAD:
316
317             switch (opcode) {
318             case FM_TUNE_OPCODE:
319
320                 if ((length == 1) && (rx_buf[i] == 1)) {
321                     FM_EVENT_SEND(link_event->ln_event, FLAG_TUNE_DONE);
322                 }
323
324                 break;
325
326             case FM_SOFT_MUTE_TUNE_OPCODE:
327
328                 if (length >= 2) {
329                     fm_memcpy(link_event->result.cqi, &rx_buf[i], (length > FM_CQI_BUF_SIZE) ? FM_CQI_BUF_SIZE : length);
330                     FM_EVENT_SEND(link_event->ln_event, FLAG_SM_TUNE);
331                 }
332                 break;
333                 
334             case FM_SEEK_OPCODE:
335
336                 if ((i + 1) < RX_BUF_SIZE) {
337                     link_event->result.seek_result = rx_buf[i] + (rx_buf[i+1] << 8); // 8760 means 87.60Mhz
338                 }
339
340                 FM_EVENT_SEND(link_event->ln_event, FLAG_SEEK_DONE);
341                 break;
342
343             case FM_SCAN_OPCODE:
344
345                 //check if the result data is long enough
346                 if ((RX_BUF_SIZE - i) < (sizeof(fm_u16) * FM_SCANTBL_SIZE)) {
347                     WCN_DBG(FM_ALT | LINK, "FM_SCAN_OPCODE err, [tblsize=%d],[bufsize=%d]\n", (sizeof(fm_u16) * FM_SCANTBL_SIZE), (RX_BUF_SIZE - i));
348                     FM_EVENT_SEND(link_event->ln_event, FLAG_SCAN_DONE);
349                     return 0;
350                 } else if ((length >= FM_CQI_BUF_SIZE) && ((RX_BUF_SIZE - i) >= FM_CQI_BUF_SIZE)) {
351                     fm_memcpy(link_event->result.cqi, &rx_buf[i], FM_CQI_BUF_SIZE);
352                     FM_EVENT_SEND(link_event->ln_event, FLAG_CQI_DONE);
353                 } else {
354                     fm_memcpy(link_event->result.scan_result, &rx_buf[i], sizeof(fm_u16) * FM_SCANTBL_SIZE);
355                     FM_EVENT_SEND(link_event->ln_event, FLAG_SCAN_DONE);
356                 }
357
358                 break;
359
360             case FSPI_READ_OPCODE:
361
362                 if ((i + 1) < RX_BUF_SIZE) {
363                     link_event->result.fspi_rd = (rx_buf[i] + (rx_buf[i+1] << 8));
364                 }
365
366                 FM_EVENT_SEND(link_event->ln_event, (1 << opcode));
367                 break;
368
369             case RDS_RX_DATA_OPCODE:
370
371                 //check if the rds data is long enough
372                 if ((RX_BUF_SIZE - i) < length) {
373                     WCN_DBG(FM_ALT | LINK, "RDS RX err, [rxlen=%d],[bufsize=%d]\n", (fm_s32)length, (RX_BUF_SIZE - i));
374                     FM_EVENT_SEND(link_event->ln_event, (1 << opcode));
375                     break;
376                 }
377
378                 //copy rds data to rds buf
379                 fm_memcpy(&link_event->result.rds_rx_result, &rx_buf[i], length);
380
381                 /*Handle the RDS data that we get*/
382                 if (rds_parser) {
383                     rds_parser(&link_event->result.rds_rx_result, length);
384                 } else {
385                     WCN_DBG(FM_WAR | LINK, "no method to parse RDS data\n");
386                 }
387
388                 FM_EVENT_SEND(link_event->ln_event, (1 << opcode));
389                 break;
390
391             default:
392                 FM_EVENT_SEND(link_event->ln_event, (1 << opcode));
393                 break;
394             }
395
396             state = FM_TASK_RX_PARSER_PKT_TYPE;
397             i += length;
398             break;
399
400         default:
401             break;
402         }
403     }
404
405     return 0;
406 }
407
408 fm_bool fm_wait_stc_done(fm_u32 sec)
409 {
410     return fm_true;
411 }
412
413 fm_s32 fm_force_active_event(fm_u32 mask)
414 {
415     fm_u32 flag;
416
417     flag = FM_EVENT_GET(link_event->ln_event);
418     WCN_DBG(FM_WAR | LINK, "before force active event, [flag=0x%08x]\n", flag);
419     flag = FM_EVENT_SEND(link_event->ln_event, mask);
420     WCN_DBG(FM_WAR | LINK, "after force active event, [flag=0x%08x]\n", flag);
421
422     return 0;
423 }
424
425
426 extern fm_s32 fm_print_cmd_fifo(void)
427 {
428 #ifdef FM_TRACE_ENABLE
429     struct fm_trace_t trace;
430     fm_s32 i = 0;
431     
432     while (fm_false == FM_TRACE_EMPTY(cmd_fifo)) {
433         fm_memset(trace.pkt, 0, FM_TRACE_PKT_SIZE);
434         FM_TRACE_OUT(cmd_fifo, &trace);
435         WCN_DBG(FM_ALT | LINK, "trace, type %d, op %d, len %d, tid %d, time %d\n", trace.type, trace.opcode, trace.len, trace.tid, jiffies_to_msecs(abs(trace.time)));
436         i = 0;
437         while ((trace.len > 0) && (i < trace.len) && (i < (FM_TRACE_PKT_SIZE-8))) {
438             WCN_DBG(FM_ALT | LINK, "trace, %02x %02x %02x %02x %02x %02x %02x %02x\n", \
439                 trace.pkt[i], trace.pkt[i+1], trace.pkt[i+2], trace.pkt[i+3], trace.pkt[i+4], trace.pkt[i+5], trace.pkt[i+6], trace.pkt[i+7]);
440             i += 8;
441         }
442         WCN_DBG(FM_ALT | LINK, "trace\n");
443     }
444 #endif
445
446     return 0;
447 }
448
449 extern fm_s32 fm_print_evt_fifo(void)
450 {
451 #ifdef FM_TRACE_ENABLE
452     struct fm_trace_t trace;
453     fm_s32 i = 0;
454     
455     while (fm_false == FM_TRACE_EMPTY(evt_fifo)) {
456         fm_memset(trace.pkt, 0, FM_TRACE_PKT_SIZE);
457         FM_TRACE_OUT(evt_fifo, &trace);
458         WCN_DBG(FM_ALT | LINK, "%s: op %d, len %d, %d\n", evt_fifo->name, trace.opcode, trace.len, jiffies_to_msecs(abs(trace.time)));
459         i = 0;
460         while ((trace.len > 0) && (i < trace.len) && (i < (FM_TRACE_PKT_SIZE-8))) {
461             WCN_DBG(FM_ALT | LINK, "%s: %02x %02x %02x %02x %02x %02x %02x %02x\n", \
462                 evt_fifo->name, trace.pkt[i], trace.pkt[i+1], trace.pkt[i+2], trace.pkt[i+3], trace.pkt[i+4], trace.pkt[i+5], trace.pkt[i+6], trace.pkt[i+7]);
463             i += 8;
464         }
465         WCN_DBG(FM_ALT | LINK, "%s\n", evt_fifo->name);
466     }
467 #endif
468
469     return 0;
470 }
471 #endif