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