media: radio: s610: fix indentation warning
[GitHub/moto-9609/android_kernel_motorola_exynos9610.git] / drivers / media / radio / s610 / fm_rds.c
CommitLineData
eb1143a3
YK
1
2#include "fm_low_struc.h"
3#include "radio-s610.h"
4#include "fm_rds.h"
5extern struct s610_radio *gradio;
6
7#ifdef USE_RINGBUFF_API
8void ringbuf_reset(struct ringbuf_t *rb)
9{
10 rb->head = rb->tail = rb->buf;
11}
12
13int ringbuf_buffer_size(const struct ringbuf_t *rb)
14{
15 return rb->size;
16}
17
18int ringbuf_capacity(const struct ringbuf_t *rb)
19{
20 return ringbuf_buffer_size(rb) - 1;
21}
22
23static const u8 *ringbuf_end(const struct ringbuf_t *rb)
24{
25 return rb->buf + ringbuf_buffer_size(rb);
26}
27
28int ringbuf_bytes_free(const struct ringbuf_t *rb)
29{
30 if (rb->head >= rb->tail)
31 return ringbuf_capacity(rb) - (rb->head - rb->tail);
32 else
33 return rb->tail - rb->head - 1;
34}
35
36int ringbuf_bytes_used(const struct ringbuf_t *rb)
37{
38 return ringbuf_capacity(rb) - ringbuf_bytes_free(rb);
39}
40
41int ringbuf_is_full(const struct ringbuf_t *rb)
42{
43 return ringbuf_bytes_free(rb) == 0;
44}
45
46int ringbuf_is_empty(const struct ringbuf_t *rb)
47{
48 return ringbuf_bytes_free(rb) == ringbuf_capacity(rb);
49}
50
51const void *ringbuf_tail(const struct ringbuf_t *rb)
52{
53 return rb->tail;
54}
55
56const void *ringbuf_head(const struct ringbuf_t *rb)
57{
58 return rb->head;
59}
60
61static u8 *ringbuf_nextp(struct ringbuf_t *rb, const u8 *p)
62{
63 /*
64 * The assert guarantees the expression (++p - rb->buf) is
65 * non-negative; therefore, the modulus operation is safe and
66 * portable.
67 */
68 return rb->buf + ((++p - rb->buf) % ringbuf_buffer_size(rb));
69}
70
71void *ringbuf_memcpy_into(struct ringbuf_t *dst, const void *src, int count)
72{
73 const u8 *u8src = src;
74 const u8 *bufend = ringbuf_end(dst);
75 int overflow = count > ringbuf_bytes_free(dst);
76 int nread = 0;
77 int n = 0;
78
79 while (nread != count) {
80 n = MIN(bufend - dst->head, count - nread);
81 memcpy(dst->head, u8src + nread, n);
82 dst->head += n;
83 nread += n;
84
85 /* wrap? */
86 if (dst->head == bufend)
87 dst->head = dst->buf;
88 }
89
90 if (overflow)
91 dst->tail = ringbuf_nextp(dst, dst->head);
92
93 return dst->head;
94}
95
96void *ringbuf_memcpy_from(void *dst, struct ringbuf_t *src, int count)
97{
98 int n = 0;
99 int bytes_used = ringbuf_bytes_used(src);
100 u8 *u8dst = dst;
101 const u8 *bufend = ringbuf_end(src);
102 int nwritten = 0;
103
104 if (count > bytes_used)
105 return 0;
106
107 while (nwritten != count) {
108 n = MIN(bufend - src->tail, count - nwritten);
109 memcpy(u8dst + nwritten, src->tail, n);
110 src->tail += n;
111 nwritten += n;
112
113 /* wrap ? */
114 if (src->tail == bufend)
115 src->tail = src->buf;
116 }
117
118 return src->tail;
119}
120
121void * ringbuf_memcpy_remove(struct ringbuf_t *dst, int count)
122{
123 int n = 0;
124 int bytes_used = ringbuf_bytes_used(dst);
125 const u8 *bufend = ringbuf_end(dst);
126 int nwritten = 0;
127 unsigned char *cls_start;
128
129 if (count > bytes_used)
130 return 0;
131
132 while (nwritten != count) {
133 n = MIN(bufend - dst->head, count - nwritten);
134 cls_start = dst->head - n;
135 memset(cls_start, 0, n);
136 dst->head -= n;
137 nwritten += n;
138
139 /* wrap ? */
140 if (dst->head == bufend)
141 dst->head = dst->buf;
142 }
143
144 return dst->head;
145}
146#endif /* USE_RINGBUFF_API */
147
148#ifdef USE_RINGBUFF_API
149void fm_rds_write_data(struct s610_radio *radio,
150 u16 rds_data, fm_rds_block_type_enum blk_type,
151 fm_host_rds_errors_enum errors)
152{
153 u8 buf_ptr[HOST_RDS_BLOCK_SIZE];
154 u16 usage;
155
156 if (ringbuf_is_full(&radio->rds_rb)) {
e16618ee 157 RDSEBUG(radio, "%s():>>>RB full! H[%ld]T[%ld]",
eb1143a3
YK
158 __func__,
159 (unsigned long) (radio->rds_rb.head - radio->rds_rb.buf),
160 (unsigned long) (radio->rds_rb.tail - radio->rds_rb.buf));
161
162 goto skip_into_buf;
163 }
164
165 buf_ptr[HOST_RDS_BLOCK_FMT_LSB] = (u8)(rds_data & 0xff);
166 buf_ptr[HOST_RDS_BLOCK_FMT_MSB] = (u8)(rds_data >> 8);
167 buf_ptr[HOST_RDS_BLOCK_FMT_STATUS] =
168 (blk_type << HOST_RDS_DATA_BLKTYPE_POSI)
169 | (errors << HOST_RDS_DATA_ERRORS_POSI)
170 | HOST_RDS_DATA_AVAIL_MASK;
171
172 if (!ringbuf_memcpy_into(&radio->rds_rb, buf_ptr, HOST_RDS_BLOCK_SIZE)) {
173 usage = ringbuf_bytes_used(&radio->rds_rb);
e16618ee 174 RDSEBUG(radio,
eb1143a3
YK
175 "%s():>>>RB memcpy into fail! usage:%04d",
176 __func__, ringbuf_bytes_used(&radio->rds_rb));
177 if (!usage)
178 return;
179 }
180
181skip_into_buf:
182 usage = ringbuf_bytes_used(&radio->rds_rb);
183
184 if (usage >= HOST_RDS_BLOCK_SIZE)
185 radio->low->fm_state.status |= STATUS_MASK_RDS_AVA;
186
187 if (radio->low->fm_state.rds_mem_thresh != 0) {
188 if (usage >= (radio->low->fm_state.rds_mem_thresh+(HOST_RDS_BLOCK_SIZE*4))) {
189 if (atomic_read(&radio->is_rds_new))
190 return;
191
192 fm_set_flag_bits(radio, FLAG_BUF_FUL);
193 atomic_set(&radio->is_rds_new, 1);
194 wake_up_interruptible(&radio->core->rds_read_queue);
195 radio->rds_n_count++;
196
197 if (!(radio->rds_n_count%200)) {
198 fm_update_rssi_work(radio);
e16618ee 199 RDSEBUG(radio,
eb1143a3
YK
200 ">>>[FM] RSSI[%03d] NCOUNT[%08d] FIFO_ERR[%08d] USAGE[%04d] SYNCLOSS[%08d]",
201 radio->low->fm_state.rssi, radio->rds_n_count, radio->rds_fifo_err_cnt,
202 usage, radio->rds_sync_loss_cnt);
203 }
204 }
205 }
206}
207#else /* USE_RINGBUFF_API */
208void fm_rds_write_data(struct s610_radio *radio, u16 rds_data,
209 fm_rds_block_type_enum blk_type, fm_host_rds_errors_enum errors)
210{
211 u8 *buf_ptr;
212 u16 usage;
213 u16 capa;
214
215 capa = radio->low->rds_buffer->size;
216 if (radio->low->rds_buffer->outdex
217 > radio->low->rds_buffer->index)
218 usage = radio->low->rds_buffer->size
219 - radio->low->rds_buffer->outdex
220 + radio->low->rds_buffer->index;
221 else
222 usage = radio->low->rds_buffer->index
223 - radio->low->rds_buffer->outdex;
224
225 if ((capa - usage) >= (HOST_RDS_BLOCK_SIZE * 4)) {
226 buf_ptr = radio->low->rds_buffer->base
227 + radio->low->rds_buffer->index;
228
229 buf_ptr[HOST_RDS_BLOCK_FMT_LSB] = (u8)(rds_data & 0xff);
230 buf_ptr[HOST_RDS_BLOCK_FMT_MSB] = (u8) (rds_data >> 8);
231 buf_ptr[HOST_RDS_BLOCK_FMT_STATUS] = (blk_type
232 << HOST_RDS_DATA_BLKTYPE_POSI)
233 | (errors << HOST_RDS_DATA_ERRORS_POSI)
234 | HOST_RDS_DATA_AVAIL_MASK;
235
236 /* Advances the buffer's index */
237 radio->low->rds_buffer->index
238 += HOST_RDS_BLOCK_SIZE;
239
240 /* Check if the buffer's index wraps */
241 if (radio->low->rds_buffer->index >=
242 radio->low->rds_buffer->size) {
243 radio->low->rds_buffer->index -=
244 radio->low->rds_buffer->size;
245 }
246
247 if (usage >= HOST_RDS_BLOCK_SIZE)
248 radio->low->fm_state.status |= STATUS_MASK_RDS_AVA;
249
250 }
251
252 if (radio->low->fm_state.rds_mem_thresh != 0) {
253 if (usage >= (radio->low->fm_state.rds_mem_thresh+(HOST_RDS_BLOCK_SIZE*4)
254 /** HOST_RDS_BLOCK_SIZE*/)) {
255 if (atomic_read(&radio->is_rds_new))
256 return;
257
258 fm_set_flag_bits(radio, FLAG_BUF_FUL);
259 atomic_set(&radio->is_rds_new, 1);
260 wake_up_interruptible(&radio->core->rds_read_queue);
261 radio->rds_n_count++;
262
263 if (!(radio->rds_n_count%200)) {
264 fm_update_rssi_work(radio);
265 dev_info(radio->dev,
266 ">>>[FM] RSSI[%03d] NCOUNT[%08d] FIFO_ERR[%08d] USAGE[%04d] SYNCLOSS[%08d]",
267 radio->low->fm_state.rssi, radio->rds_n_count, radio->rds_fifo_err_cnt,
268 usage, radio->rds_sync_loss_cnt);
269 }
270 }
271 }
272}
273#endif /* USE_RINGBUFF_API */
274
275#ifdef USE_RDS_BLOCK_SEQ_CORRECT
276#ifdef USE_RINGBUFF_API
277void fm_rds_write_data_remove(struct s610_radio *radio,
278 fm_rds_rm_align_enum removeblock)
279{
280 unsigned long pre_head, cur_head;
281 pre_head = (unsigned long) radio->rds_rb.head;
282 ringbuf_memcpy_remove(&radio->rds_rb,
283 (int)removeblock*HOST_RDS_BLOCK_SIZE);
284 cur_head = (unsigned long) radio->rds_rb.head;
e16618ee 285 RDSEBUG(radio, ">>> pre-head :%08lX, cur-head :%08lX\n",
eb1143a3
YK
286 pre_head, cur_head);
287}
288#else
289void fm_rds_write_data_remove(struct s610_radio *radio,
290 fm_rds_rm_align_enum removeblock)
291{
292 int i;
293 u8 *buf_ptr;
294
295 for (i = 0; i < removeblock*HOST_RDS_BLOCK_SIZE; i++) {
296 buf_ptr = radio->low->rds_buffer->base
297 + radio->low->rds_buffer->index;
298 buf_ptr[0] = 0;
299 if (radio->low->rds_buffer->index == 0)
300 radio->low->rds_buffer->index = radio->low->rds_buffer->size;
301 radio->low->rds_buffer->index--;
302 }
303 RDSEBUG(radio, "%s():<<<WR-RM:%d index[%04d]",
304 __func__, removeblock,
305 radio->low->rds_buffer->index);
306
307}
308#endif /*USE_RINGBUFF_API*/
309#endif /* USE_RDS_BLOCK_SEQ_CORRECT */
310
311#ifdef USE_RINGBUFF_API
312int fm_read_rds_data(struct s610_radio *radio, u8 *buffer, int size,
313 u16 *blocks)
314{
315 u16 rsize = size;
316
317 if (ringbuf_is_empty(&radio->rds_rb)) {
e16618ee 318 RDSEBUG(radio,
eb1143a3
YK
319 "%s():>>>RB empty!! H[%04ld]T[%04ld]",
320 __func__,
321 (unsigned long) (radio->rds_rb.head - radio->rds_rb.buf),
322 (unsigned long) (radio->rds_rb.tail - radio->rds_rb.buf));
323
324 return 0;
325 }
326 radio->rb_used = ringbuf_bytes_used(&radio->rds_rb);
327 if (!ringbuf_memcpy_from(buffer, &radio->rds_rb, rsize)) {
e16618ee 328 RDSEBUG(radio,
eb1143a3
YK
329 "%s():>>>RB memcpy from fail! H[%04ld]T[%04ld]",
330 __func__,
331 (unsigned long) (radio->rds_rb.head - radio->rds_rb.buf),
332 (unsigned long) (radio->rds_rb.tail - radio->rds_rb.buf));
333
334 /* ringbuff reset */
335 ringbuf_reset(&radio->rds_rb);
336 if (blocks)
337 blocks = 0;
338 return 0;
339 }
340
341 if (blocks)
342 *blocks = rsize / HOST_RDS_BLOCK_SIZE;
343
344 /* Update RDS flags */
345 if ((rsize / HOST_RDS_BLOCK_SIZE) < radio->low->fm_state.rds_mem_thresh)
346 fm_clear_flag_bits(radio, FLAG_BUF_FUL);
347
348 RDSEBUG(radio,
349 "%s():>>>RB1 H[%04ld]T[%04ld]",
350 __func__,
351 (unsigned long) (radio->rds_rb.head - radio->rds_rb.buf),
352 (unsigned long) (radio->rds_rb.tail - radio->rds_rb.buf));
353
354 return rsize;
355}
356#else /* USE_RINGBUFF_API */
357u16 fm_rds_get_avail_bytes(struct s610_radio *radio)
358{
359 u16 avail_bytes;
360
361 if (radio->low->rds_buffer->outdex >
362 radio->low->rds_buffer->index)
363 avail_bytes = (radio->low->rds_buffer->size
364 - radio->low->rds_buffer->outdex
365 + radio->low->rds_buffer->index);
366 else
367 avail_bytes = (radio->low->rds_buffer->index
368 - radio->low->rds_buffer->outdex);
369
370 return avail_bytes;
371}
372
373
374int fm_read_rds_data(struct s610_radio *radio, u8 *buffer, int size,
375 u16 *blocks)
376{
377 u16 avail_bytes;
378 s16 avail_blocks;
379 s16 orig_avail;
380 u8 *buf_ptr;
381
382 if (radio->low->rds_buffer == NULL) {
383 size = 0;
384 if (blocks)
385 *blocks = 0;
386 return FALSE;
387 }
388
389 orig_avail = avail_bytes = fm_rds_get_avail_bytes(radio);
390
391 if (avail_bytes > size)
392 avail_bytes = size;
393
394 avail_blocks = avail_bytes / HOST_RDS_BLOCK_SIZE;
395 avail_bytes = avail_blocks * HOST_RDS_BLOCK_SIZE;
396
397 if (avail_bytes == 0) {
398 size = 0;
399 if (blocks)
400 *blocks = 0;
401 return FALSE;
402 }
403
404 buf_ptr = radio->low->rds_buffer->base
405 + radio->low->rds_buffer->outdex;
406 (void) memcpy(buffer, buf_ptr, avail_bytes);
407
408 /* advances the buffer's outdex */
409 radio->low->rds_buffer->outdex += avail_bytes;
410
411 /* Check if the buffer's outdex wraps */
412 if (radio->low->rds_buffer->outdex >= radio->low->rds_buffer->size)
413 radio->low->rds_buffer->outdex -= radio->low->rds_buffer->size;
414
415 if (orig_avail == avail_bytes) {
416 buffer[(avail_blocks - 1) * HOST_RDS_BLOCK_SIZE
417 + HOST_RDS_BLOCK_FMT_STATUS] &=
418 ~HOST_RDS_DATA_AVAIL_MASK;
419 radio->low->fm_state.status &= ~STATUS_MASK_RDS_AVA;
420 }
421
422 size = avail_bytes; /* number of bytes read */
423
424 if (blocks)
425 *blocks = avail_bytes / HOST_RDS_BLOCK_SIZE;
426
427 /* Update RDS flags */
428 if ((avail_bytes / HOST_RDS_BLOCK_SIZE)
429 < radio->low->fm_state.rds_mem_thresh)
430 fm_clear_flag_bits(radio, FLAG_BUF_FUL);
431
432 return size;
433}
434#endif /* USE_RINGBUFF_API */
435
436#ifdef USE_RDS_HW_DECODER
437void fm_rds_change_state(struct s610_radio *radio,
438 fm_rds_state_enum new_state)
439{
440 fm_rds_state_enum old_state =
441 (fm_rds_state_enum) radio->low->fm_rds_state.current_state;
442
443 radio->low->fm_rds_state.current_state = new_state;
444
445 if ((old_state == RDS_STATE_FULL_SYNC)
446 && (new_state == RDS_STATE_HAVE_DATA)) {
447 fm_update_rds_sync_status(radio, FALSE); /* unsynced */
448 } else if ((old_state != RDS_STATE_FULL_SYNC)
449 && (new_state == RDS_STATE_FULL_SYNC)) {
450 fm_update_rds_sync_status(radio, TRUE); /* synced */
451 }
452}
453#else /*USE_RDS_HW_DECODER*/
454void fm_rds_change_state(struct s610_radio *radio,
455 fm_rds_state_enum new_state)
456{
457 radio->low->fm_rds_state.current_state = new_state;
458}
459
460fm_rds_state_enum fm_rds_get_state(struct s610_radio *radio)
461{
462 return radio->low->fm_rds_state.current_state;
463}
464#endif /*USE_RDS_HW_DECODER*/
465
466void fm_rds_update_error_status(struct s610_radio *radio, u16 errors)
467{
468 if (errors == 0) {
469 radio->low->fm_rds_state.error_bits = 0;
470 radio->low->fm_rds_state.error_blks = 0;
471 } else {
472 radio->low->fm_rds_state.error_bits += errors;
473 radio->low->fm_rds_state.error_blks++;
474 }
475
476 if (radio->low->fm_rds_state.error_blks
477 >= radio->low->fm_state.rds_unsync_blk_cnt) {
478 if (radio->low->fm_rds_state.error_bits
479 >= radio->low->fm_state.rds_unsync_bit_cnt) {
480 /* sync-loss */
481 fm_rds_change_state(radio, RDS_STATE_HAVE_DATA);
482 RDSEBUG(radio, "%s() >>>>> RDS sync-loss[%08d]!!!!!",
483 __func__, radio->rds_sync_loss_cnt);
484
485#ifdef USE_RDS_HW_DECODER
486 fm_rds_change_state(radio, RDS_STATE_HAVE_DATA);
487#else
488 if (!radio->rds_sync_loss_cnt) {
489#ifdef USE_RINGBUFF_API
490 ringbuf_reset(&radio->rds_rb);
491#else
492 radio->low->rds_buffer->index = radio->low->rds_buffer->outdex = 0;
493#endif
494 } else {
495 /*remove data*/
e6869d40 496 fm_rds_write_data_remove(radio, (fm_rds_rm_align_enum)fm_rds_get_state(radio));
eb1143a3
YK
497 }
498 fm_rds_change_state(radio, RDS_STATE_INIT);
499#endif /*USE_RDS_HW_DECODER*/
500 }
501 radio->low->fm_rds_state.error_bits = 0;
502 radio->low->fm_rds_state.error_blks = 0;
503 radio->rds_sync_loss_cnt++;
504 }
505}
506
507static fm_host_rds_errors_enum fm_rds_process_block(
508 struct s610_radio *radio,
509 u16 data, fm_rds_block_type_enum block_type,
510 u16 err_count)
511{
512 fm_host_rds_errors_enum error_type;
513 struct fm_rds_parser_info *pi;
514
515 if (radio->rds_parser_enable)
516 pi = &(radio->pi);
517
518 if (err_count == 0) {
519 error_type = HOST_RDS_ERRS_NONE;
520 } else if ((err_count <= 2)
521 && (err_count
522 <= radio->low->fm_config.rds_error_limit)) {
523 error_type = HOST_RDS_ERRS_2CORR;
524 } else if ((err_count <= 5)
525 && (err_count
526 <= radio->low->fm_config.rds_error_limit)) {
527 error_type = HOST_RDS_ERRS_5CORR;
528 } else {
529 error_type = HOST_RDS_ERRS_UNCORR;
530 }
531
532 /* Write the data into the buffer */
533 if ((block_type != RDS_BLKTYPE_E)
534 || (radio->low->fm_state.save_eblks)) {
535 if (radio->rds_parser_enable) {
536 fm_rds_parser(pi, data, block_type, error_type);
537 fm_rds_write_data_pi(radio, pi);
538 } else {
e16618ee
YK
539 fm_rds_write_data(radio, data, block_type, error_type);
540 }
eb1143a3
YK
541 }
542
543 return error_type;
544}
545
546#ifdef USE_RDS_BLOCK_SEQ_CORRECT
547fm_rds_rm_align_enum fm_check_block_seq(fm_rds_block_type_enum pre_block_type,
548 fm_rds_block_type_enum curr_block_type)
549{
550 fm_rds_rm_align_enum ret = RDS_RM_ALIGN_NONE;
551
552 if ((pre_block_type == RDS_BLKTYPE_A) && (curr_block_type != RDS_BLKTYPE_B)) {
553 ret = RDS_RM_ALIGN_1;
554 }
555 else if ((pre_block_type == RDS_BLKTYPE_B) && (curr_block_type != RDS_BLKTYPE_C)) {
556 ret = RDS_RM_ALIGN_2;
557 }
558 else if ((pre_block_type == RDS_BLKTYPE_C) && (curr_block_type != RDS_BLKTYPE_D)) {
559 ret = RDS_RM_ALIGN_3;
560 }
561 else if ((pre_block_type == RDS_BLKTYPE_D) && (curr_block_type != RDS_BLKTYPE_A)) {
562 ret = RDS_RM_ALIGN_0;
563 }
564 return ret;
565}
566#endif /* USE_RDS_BLOCK_SEQ_CORRECT */
567
568#ifdef USE_RDS_HW_DECODER
569void fm_process_rds_data(struct s610_radio *radio)
570{
571 u32 fifo_data;
572 u16 i;
573 u16 avail_blocks;
574 u16 data;
575 u8 status;
576 u16 err_count;
577 fm_rds_block_type_enum block_type;
578#ifdef USE_RDS_BLOCK_SEQ_CORRECT
579 fm_rds_rm_align_enum rm_blk = RDS_RM_ALIGN_NONE;
580#endif /* USE_RDS_BLOCK_SEQ_CORRECT */
581
582 API_ENTRY(radio);
583
584 if (!radio->low->fm_state.rds_rx_enabled)
585 return;
586
587 avail_blocks = RDS_MEM_MAX_THRESH/4;
588
589 for (i = 0; i < avail_blocks; i++) {
590 /* Fetch the RDS word data. */
591 atomic_set(&radio->is_rds_doing, 1);
592 fifo_data = fmspeedy_get_reg_work(0xFFF3C0);
593 radio->rds_fifo_rd_cnt++;
594 data = (u16)((fifo_data >> 16) & 0xFFFF);
595 status = (u8)((fifo_data >> 8) & 0xFF);
596 block_type =
597 (fm_rds_block_type_enum) ((status & RDS_BLK_TYPE_MASK)
598 >> RDS_BLK_TYPE_SHIFT);
599 err_count = (status & RDS_ERR_CNT_MASK);
600 atomic_set(&radio->is_rds_doing, 0);
601
602 switch (radio->low->fm_rds_state.current_state) {
603 case RDS_STATE_INIT:
604 APIEBUG(radio, "RDS_STATE_INIT");
605 fm_rds_change_state(radio, RDS_STATE_HAVE_DATA);
606 case RDS_STATE_HAVE_DATA:
607 APIEBUG(radio, "RDS_STATE_HAVE_DATA");
608 if ((block_type == RDS_BLKTYPE_A)
609 && (err_count == 0)) {
610#ifdef USE_RDS_BLOCK_SEQ_CORRECT
611 radio->block_seq = RDS_BLKTYPE_A;
612#endif /*USE_RDS_BLOCK_SEQ_CORRECT */
613 /* Move to full sync */
614 fm_rds_change_state(radio,
615 RDS_STATE_FULL_SYNC);
616 fm_rds_process_block(radio,
617 data, block_type, err_count);
618 }
619 break;
620 case RDS_STATE_PRE_SYNC:
621 break;
622 case RDS_STATE_FULL_SYNC:
623 APIEBUG(radio, "RDS_STATE_FULL_SYNC");
624#ifdef USE_RDS_BLOCK_SEQ_CORRECT
625 rm_blk = fm_check_block_seq(radio->block_seq, block_type);
626 if (rm_blk < RDS_RM_ALIGN_NONE) {
627 RDSEBUG(radio,
628 "pre block[%02d],curr block[%02d],err count[%08d]",
629 radio->block_seq, block_type, radio->rds_fifo_err_cnt);
630 if (rm_blk != RDS_RM_ALIGN_0) {
631 fm_rds_write_data_remove(radio, rm_blk);
632 radio->block_seq = RDS_BLKTYPE_D;
633 }
634 fm_rds_change_state(radio, RDS_STATE_HAVE_DATA);
635 radio->rds_fifo_err_cnt++;
636 break;
637 }
638 radio->block_seq = block_type;
639#endif /* USE_RDS_BLOCK_SEQ_CORRECT */
640 if (fm_rds_process_block(radio,
641 data, block_type, err_count)
642 == HOST_RDS_ERRS_UNCORR) {
643 fm_rds_update_error_status(radio,
644 radio->low->fm_state.rds_unsync_uncorr_weight);
645 } else {
646 fm_rds_update_error_status(radio, err_count);
647 }
648 break;
649 }
650 }
651
652 API_EXIT(radio);
653}
654#endif /* USE_RDS_HW_DECODER */
655void find_pi_data(struct fm_rds_parser_info *pi, u16 info)
656{
657
658 pi->pi_buf[pi->pi_idx % 2] = info;
659
660 if (!(++pi->pi_idx % 2)) {
661 if (pi->pi_buf[0] == pi->pi_buf[1]) {
662 pi->rds_event |= RDS_EVENT_PI_MASK;
663 RDSEBUG(gradio, "[RDS] PI : 0x%x\n", pi->pi_buf[0]);
664 }
665 }
666}
667
668void find_ecc_data(struct fm_rds_parser_info *pi, u16 info)
669{
670
671 pi->ecc_buf[pi->ecc_idx % 2] = info & 0xFF;
672
673 if (!(++pi->ecc_idx % 2)) {
674 if (pi->ecc_buf[0] == pi->ecc_buf[1]) {
675 pi->rds_event |= RDS_EVENT_ECC_MASK;
676 RDSEBUG(gradio, "[RDS] ECC : %d\n", pi->ecc_buf[0]);
677 }
678 }
679}
680
681void store_ps_data(struct fm_rds_parser_info *pi,
682 u16 info, u8 err_cnt)
683{
684 char a, b;
685 u32 i = pi->ps_idx % 3;
686 u8 seg = pi->ps_segment;
687
688 if (pi->drop_blk)
689 return;
690
691 a = (info >> 8) & 0xff;
692 b = info & 0xff;
693
694 pi->ps_buf[i][seg * 2] = a;
695 pi->ps_buf[i][seg * 2 + 1] = b;
696 pi->ps_err[i][seg] = err_cnt;
697 /*RDSEBUG(gradio,
698 "[RDS] PS: [%c][%c] [%d][%d], modulo idx=%d, seg=%d\n",
699 a, b, (int)a, (int)b, i, seg);*/
700}
701
702void validate_ps_data(struct fm_rds_parser_info *pi)
703{
704 u32 i;
705 bool match = true;
706
707 for (i = 0; i < pi->ps_len / 2; i++) {
708 if (pi->ps_err[pi->ps_idx % 3][i] > 0)
709 break;
710 }
711
712 if (i == pi->ps_len / 2) {
713 memcpy(pi->ps_candidate,
714 pi->ps_buf[pi->ps_idx % 3],
715 pi->ps_len);
716 memset(pi->ps_err[pi->ps_idx % 3],
717 0xFF, MAX_PS / 2);
718 pi->ps_candidate[pi->ps_len] = 0;
719 pi->rds_event |= RDS_EVENT_PS_MASK;
720 pi->ps_idx++;
721 RDSEBUG(gradio,
722 "[RDS] ### PS candidate[i]: %s\n",
723 pi->ps_candidate);
724 } else {
725 if (++pi->ps_idx >= 3) {
726 for (i = 0; i < pi->ps_len; i++) {
727 if (pi->ps_buf[0][i] == pi->ps_buf[1][i])
728 pi->ps_candidate[i] = pi->ps_buf[0][i];
729 else if (pi->ps_buf[0][i] == pi->ps_buf[2][i])
730 pi->ps_candidate[i] = pi->ps_buf[0][i];
731 else if (pi->ps_buf[1][i] == pi->ps_buf[2][i])
732 pi->ps_candidate[i] = pi->ps_buf[1][i];
733 else
734 match = false;
735 }
736
737 if (match) {
738 pi->ps_candidate[pi->ps_len] = 0;
739 pi->rds_event |= RDS_EVENT_PS_MASK;
740 RDSEBUG(gradio,
741 "[RDS] ### PS candidate[m]: %s\n",
742 pi->ps_candidate);
743 }
744 }
745 }
746
747 i = pi->ps_idx - 1;
748 pi->ps_buf[i % 3][pi->ps_len] = 0;
749
750 for (i = 0; i < 3; i++)
751 RDSEBUG(gradio,
752 "[RDS] ### PS received[%d]: %s\n",
753 i, pi->ps_buf[i]);
754}
755
756void store_rt_data(struct fm_rds_parser_info *pi, u16 info, u8 blk_type, u8 err_cnt)
757{
758 char a, b;
759 u32 i = pi->rt_idx % 3;
760 u8 seg = pi->rt_segment;
761
762 if (pi->drop_blk)
763 return;
764
765 a = (info >> 8) & 0xff;
766 b = info & 0xff;
767
768 switch (blk_type) {
769 case RDS_BLKTYPE_C:
770 pi->rt_buf[i][seg * 4] = a;
771 pi->rt_buf[i][seg * 4 + 1] = b;
772 pi->rt_err[i][seg * 2] = err_cnt;
773 /*RDSEBUG(gradio,
774 "[RDS] RT_A(C): [%c][%c] [%d][%d], modulo idx=%d, seg=%d\n",
775 a, b, (int)a, (int)b, i, seg);*/
776 break;
777
778 case RDS_BLKTYPE_D:
779 if (pi->grp == RDS_GRPTYPE_2A) {
780 pi->rt_buf[i][seg * 4 + 2] = a;
781 pi->rt_buf[i][seg * 4 + 3] = b;
782 pi->rt_err[i][seg * 2 + 1] = err_cnt;
783 /*RDSEBUG(gradio,
784 "[RDS] RT_A(D): [%c][%c] [%d][%d], modulo idx=%d, seg=%d\n",
785 a, b, (int)a, (int)b, i, seg);*/
786 } else if (pi->grp == RDS_GRPTYPE_2B) {
787 pi->rt_buf[i][seg * 2] = a;
788 pi->rt_buf[i][seg * 2 + 1] = b;
789 pi->rt_err[i][seg] = err_cnt;
790 /*RDSEBUG(gradio,
791 "[RDS] RT_B(C): [%c][%c] [%d][%d], modulo idx=%d, seg=%d\n",
792 a, b, (int)a, (int)b, i, seg);*/
793 }
794 default:
795 break;
796 }
797}
798
799void validate_rt_data(struct fm_rds_parser_info *pi)
800{
801 u32 i;
802 bool match = true;
803
804 for (i = 0; i < pi->rt_len / 2; i++) {
805 if (pi->rt_err[pi->rt_idx % 3][i] > 0)
806 break;
807 }
808
809 if (i == pi->rt_len / 2) {
810 memcpy(pi->rt_candidate, pi->rt_buf[pi->rt_idx % 3], pi->rt_len);
811 memset(pi->rt_err[pi->rt_idx % 3], 0xFF, MAX_RT / 2);
812 pi->rt_candidate[pi->rt_len] = 0;
813
c2fb5b4c 814 if (strlen(pi->rt_candidate) >= (pi->rt_len - 2)) {
eb1143a3
YK
815 pi->rds_event |= RDS_EVENT_RT_MASK;
816 pi->rt_validated = 1;
817 pi->rt_idx++;
818 RDSEBUG(gradio,
819 "[RDS] ### RT candidate[i]: %s, %d, %d\n",
820 pi->rt_candidate, (int)strlen(pi->rt_candidate), pi->rt_len);
821 }
822 } else {
823 if (++pi->rt_idx >= 3) {
824 for (i = 0; i < pi->rt_len; i++) {
825 if (pi->rt_buf[0][i] == pi->rt_buf[1][i])
826 pi->rt_candidate[i] = pi->rt_buf[0][i];
827 else if (pi->rt_buf[0][i] == pi->rt_buf[2][i])
828 pi->rt_candidate[i] = pi->rt_buf[0][i];
829 else if (pi->rt_buf[1][i] == pi->rt_buf[2][i])
830 pi->rt_candidate[i] = pi->rt_buf[1][i];
831 else
832 match = false;
833 }
834
835 if (match) {
836 pi->rt_candidate[pi->rt_len] = 0;
837
c2fb5b4c 838 if (strlen(pi->rt_candidate) >= (pi->rt_len - 2)) {
eb1143a3
YK
839 pi->rds_event |= RDS_EVENT_RT_MASK;
840 pi->rt_validated = 1;
841 RDSEBUG(gradio,
842 "[RDS] ### RT candidate[m]: %s, %d, %d\n",
843 pi->rt_candidate, (int)strlen(pi->rt_candidate), pi->rt_len);
844 }
845 }
846 }
847 }
848
849 i = pi->rt_idx - 1;
850 pi->rt_buf[i % 3][pi->rt_len] = 0;
851 for (i = 0; i < 3; i++)
852 RDSEBUG(gradio,
853 "[RDS] ### RT received[%d]: %s\n",
854 i, pi->rt_buf[i]);
855}
856
857void reset_rtp_data(struct fm_rds_parser_info *pi)
858{
859 memset(&(pi->rtp_data), 0x0, sizeof(struct rtp_info));
860 memset(pi->rtp_raw_data, 0x0, sizeof(u16) * 3);
861}
862
863void validate_rtp_data(struct fm_rds_parser_info *pi)
864{
865 u8 i;
866 static u16 rtp_validated;
867 struct rtp_tag_info tag[2];
868
869 if (!pi->rtp_data.running) {
870 RDSEBUG(gradio, "[RDS] RTP running is stopped\n");
871 return;
872 }
873
874 tag[0].content_type = ((pi->rtp_raw_data[RDS_BLKTYPE_B - 1] & 0x0007) << 3) |
875 ((pi->rtp_raw_data[RDS_BLKTYPE_C - 1] & 0xE000) >> 13);
876 tag[0].start_pos = (pi->rtp_raw_data[RDS_BLKTYPE_C - 1] & 0x1F80) >> 7;
877 tag[0].len = (pi->rtp_raw_data[RDS_BLKTYPE_C - 1] & 0x007E) >> 1;
878
879 tag[1].content_type = ((pi->rtp_raw_data[RDS_BLKTYPE_C - 1] & 0x0001) << 5) |
880 ((pi->rtp_raw_data[RDS_BLKTYPE_D - 1] & 0xF800) >> 11);
881 tag[1].start_pos = (pi->rtp_raw_data[RDS_BLKTYPE_D - 1] & 0x07E0) >> 5;
882 tag[1].len = pi->rtp_raw_data[RDS_BLKTYPE_D - 1] & 0x001F;
883
884 RDSEBUG(gradio, "[RDS] RTP tag[0]:[%d,%d,%d]\n", tag[0].content_type, tag[0].start_pos, tag[0].len);
885 RDSEBUG(gradio, "[RDS] RTP tag[1]:[%d,%d,%d]\n", tag[1].content_type, tag[1].start_pos, tag[1].len);
886
887 /* Check overlap */
888 if (((tag[1].content_type != 0) && (tag[0].start_pos < tag[1].start_pos) && ((tag[0].start_pos + tag[0].len) >= tag[1].start_pos)) ||
889 ((tag[0].content_type != 0) && (tag[1].start_pos < tag[0].start_pos) && ((tag[1].start_pos + tag[1].len) >= tag[0].start_pos))) {
890 RDSEBUG(gradio, "[RDS] RTP tag[0] & tag[1] are overlapped.\n");
891 return;
892 }
893
894 for (i = 0; i < MAX_RTP_TAG; i++) {
895 if (tag[i].content_type == pi->rtp_data.tag[i].content_type &&
896 tag[i].start_pos == pi->rtp_data.tag[i].start_pos &&
897 tag[i].len == pi->rtp_data.tag[i].len) {
898 rtp_validated++;
899 RDSEBUG(gradio, "[RDS] RTP tag validation check count:0x%x\n", (int)rtp_validated);
900 } else {
901 pi->rtp_data.tag[i].content_type = tag[i].content_type;
902 pi->rtp_data.tag[i].start_pos = tag[i].start_pos;
903 pi->rtp_data.tag[i].len = tag[i].len;
904 rtp_validated = 0;
905 }
906 }
907
908 /* RT is ready to be displayed along with RTP data */
909 if (pi->rt_validated && rtp_validated > 2)
910 pi->rds_event |= RDS_EVENT_RTP_MASK;
911}
912
913void store_rtp_data(struct fm_rds_parser_info *pi, u16 info, u8 blk_type)
914{
915 u8 toggle;
916
917 if (pi->drop_blk) {
918 return;
919 }
920
921 if (pi->grp != pi->rtp_code_group) {
922 RDSEBUG(gradio, "[RDS] Received unexpected code group(0x%x), expected=0x%x\n",
923 (int)pi->grp, (int)pi->rtp_code_group);
924 return;
925 }
926
927 switch (blk_type) {
928 case RDS_BLKTYPE_B:
929 toggle = (info & 0x010) >> 4;
930 if (toggle != pi->rtp_data.toggle) {
931 reset_rtp_data(pi);
932 pi->rtp_data.toggle = toggle;
933 }
934 pi->rtp_data.running = (info & 0x0008) >> 3;
935 pi->rtp_raw_data[blk_type-1] = info;
936 RDSEBUG(gradio, "[RDS] Received RTP B block/0x%x Group\n", (int)pi->grp);
937 break;
938 case RDS_BLKTYPE_C:
939 pi->rtp_raw_data[blk_type-1] = info;
940 RDSEBUG(gradio, "[RDS] Received RTP C block/0x%x Group\n", (int)pi->grp);
941 break;
942 case RDS_BLKTYPE_D:
943 pi->rtp_raw_data[blk_type-1] = info;
944 RDSEBUG(gradio, "[RDS] Received RTP D block/0x%x Group\n", (int)pi->grp);
945 validate_rtp_data(pi);
946 break;
947 default:
948 break;
949 }
950}
951
952void find_rtp_data(struct fm_rds_parser_info *pi, u16 info, u8 blk_type)
953{
954 if (pi->drop_blk)
955 return;
956
957 switch (blk_type) {
958 case RDS_BLKTYPE_B:
959 pi->rtp_code_group = info & 0x1f;
960 RDSEBUG(gradio, "[RDS] RTP code group:0x%x\n", (int)pi->rtp_code_group);
961 break;
962 case RDS_BLKTYPE_C:
963 /* Not support SCB/RTP template */
964 RDSEBUG(gradio, "[RDS] RTP not support SCB/RTP template\n");
965 break;
966 case RDS_BLKTYPE_D:
967 if (info != RDS_RTP_AID) {
968 RDSEBUG(gradio, "[RDS] Invalid RTP aid=0x%x\n", (int)info);
969 pi->rtp_code_group = 0;
970 }
971 break;
972 default:
973 break;
974 }
975}
976
977void find_group_data(struct fm_rds_parser_info *pi, u16 info)
978{
979 u8 segment, rt_change;
980
981 pi->grp = (info >> 11) & 0x1f;
982
4e871175
YK
983 pi->pty = (info >> 5) & 0x1f;
984 pi->rds_event |= RDS_EVENT_PTY_MASK;
985
eb1143a3
YK
986 switch (pi->grp) {
987 case RDS_GRPTYPE_0A:
988 case RDS_GRPTYPE_0B:
989 segment = info & 0x3;
990
991 if (!segment && pi->ps_segment != 0xFF)
992 validate_ps_data(pi);
993
994 pi->ps_segment = segment;
995
996 if (pi->ps_len < (segment + 1) * 2)
997 pi->ps_len = (segment + 1) * 2;
998
999 /*RDSEBUG(gradio,
1000 "[RDS] PS: seg=%d, len=%d\n",
1001 segment, pi->ps_len);*/
1002 break;
1003
1004 case RDS_GRPTYPE_2A:
1005 case RDS_GRPTYPE_2B:
1006 segment = info & 0xF;
1007 rt_change = (info & 0x10) >> 4;
1008
1009 RDSEBUG(gradio,
1010 "[RDS] segment=%d, pi->rt_segment=%d, pi->rt_change=%d, rt_change=%d\n",
1011 segment, pi->rt_segment, pi->rt_change, rt_change);
1012
1013 if ((!segment && pi->rt_segment != 0xFF)
1014 || (pi->rt_change != 0xFF && pi->rt_change != rt_change)) {
1015 validate_rt_data(pi);
1016
1017 if (pi->rt_change != 0xFF && pi->rt_change != rt_change) {
1018 pi->rt_len = 0;
1019 pi->rt_idx = 0;
1020 memset(pi->rt_buf, 0, 3 * (MAX_RT + 1));
1021 memset(pi->rt_err, 0xFF, 3 * MAX_RT / 2);
1022 pi->rt_validated = 0;
1023 }
1024 }
1025
1026 pi->rt_segment = segment;
1027 pi->rt_change = rt_change;
1028
1029 if (pi->grp == RDS_GRPTYPE_2A) {
1030 if (pi->rt_len < (segment + 1) * 4)
1031 pi->rt_len = (segment + 1) * 4;
1032 } else {
1033 if (pi->rt_len < (segment + 1) * 2)
1034 pi->rt_len = (segment + 1) * 2;
1035 }
1036
1037 RDSEBUG(gradio,
1038 "[RDS] RT: seg=%d, tc=%d, len=%d\n",
1039 segment, rt_change, pi->rt_len);
1040 break;
1041
1042 case RDS_GRPTYPE_3A:
1043 find_rtp_data(pi, info, RDS_BLKTYPE_B);
1044 break;
1045
1046 case RDS_GRPTYPE_5A:
1047 case RDS_GRPTYPE_6A:
1048 case RDS_GRPTYPE_7A:
1049 case RDS_GRPTYPE_8A:
1050 case RDS_GRPTYPE_9A:
1051 case RDS_GRPTYPE_11A:
1052 case RDS_GRPTYPE_12A:
1053 case RDS_GRPTYPE_13A:
1054 store_rtp_data(pi, info, RDS_BLKTYPE_B);
1055 break;
1056
1057 default:
1058 break;
1059 }
1060}
1061
1062void find_af_data(struct fm_rds_parser_info *pi, u16 info)
1063{
1064
1065 pi->af_buf[pi->af_idx % 2] = info;
1066
1067 if (!(++pi->af_idx % 2)) {
1068 if (pi->af_buf[0] == pi->af_buf[1])
1069 pi->rds_event |= RDS_EVENT_AF_MASK;
1070 }
1071}
1072
1073void fm_rds_parser_reset(struct fm_rds_parser_info *pi)
1074{
1075 /* reset rds parser data structure */
1076 memset(pi, 0x0, sizeof(struct fm_rds_parser_info));
1077
1078 pi->ps_segment = 0xFF;
1079 pi->rt_segment = 0xFF;
1080 pi->rt_change = 0xFF;
1081 pi->rtp_data.toggle = 0xFF;
1082 memset(pi->rt_err, 0xFF, 3 * MAX_RT / 2);
1083 memset(pi->ps_err, 0xFF, 3 * MAX_PS / 2);
1084}
1085
1086void fm_rds_parser(struct fm_rds_parser_info *pi, u16 info, u8 blk_type, u8 err_cnt)
1087{
1088
1089 switch (blk_type) {
1090 case RDS_BLKTYPE_A:
1091 find_pi_data(pi, info);
1092 break;
1093
1094 case RDS_BLKTYPE_B:
1095 if (err_cnt > 2) {
1096 pi->grp = RDS_GRPTYPE_NONE;
1097 pi->drop_blk = true;
1098 break;
1099 } else {
1100 pi->drop_blk = false;
1101 }
1102
1103 find_group_data(pi, info);
1104 break;
1105
1106 case RDS_BLKTYPE_C:
1107 if (err_cnt > 5)
1108 return;
1109
1110 switch (pi->grp) {
1111 case RDS_GRPTYPE_0A:
1112 find_af_data(pi, info);
1113 break;
1114
1115 case RDS_GRPTYPE_0B:
1116 find_pi_data(pi, info);
1117 break;
1118
1119 case RDS_GRPTYPE_1A:
1120 find_ecc_data(pi, info);
1121 break;
1122
1123 case RDS_GRPTYPE_2A:
1124 store_rt_data(pi, info, blk_type, err_cnt);
1125 break;
1126
1127 case RDS_GRPTYPE_2B:
1128 find_pi_data(pi, info);
1129 break;
1130
1131 case RDS_GRPTYPE_3A:
1132 find_rtp_data(pi, info, blk_type);
1133 break;
1134
1135 case RDS_GRPTYPE_5A:
1136 case RDS_GRPTYPE_6A:
1137 case RDS_GRPTYPE_7A:
1138 case RDS_GRPTYPE_8A:
1139 case RDS_GRPTYPE_9A:
1140 case RDS_GRPTYPE_11A:
1141 case RDS_GRPTYPE_12A:
1142 case RDS_GRPTYPE_13A:
1143 store_rtp_data(pi, info, blk_type);
1144 break;
1145
1146 default:
1147 break;
1148 }
1149 break;
1150
1151 case RDS_BLKTYPE_D:
1152 if (err_cnt > 5)
1153 return;
1154
a9d2f3c7 1155 switch (pi->grp) {
eb1143a3
YK
1156 case RDS_GRPTYPE_0A:
1157 case RDS_GRPTYPE_0B:
1158 store_ps_data(pi, info, err_cnt);
1159 break;
1160
1161 case RDS_GRPTYPE_2A:
1162 case RDS_GRPTYPE_2B:
1163 store_rt_data(pi, info, blk_type, err_cnt);
1164 break;
1165
1166 case RDS_GRPTYPE_3A:
1167 find_rtp_data(pi, info, blk_type);
1168 break;
1169
1170 case RDS_GRPTYPE_5A:
1171 case RDS_GRPTYPE_6A:
1172 case RDS_GRPTYPE_7A:
1173 case RDS_GRPTYPE_8A:
1174 case RDS_GRPTYPE_9A:
1175 case RDS_GRPTYPE_11A:
1176 case RDS_GRPTYPE_12A:
1177 case RDS_GRPTYPE_13A:
1178 store_rtp_data(pi, info, blk_type);
1179 break;
1180
1181 default:
1182 break;
a9d2f3c7
S
1183 }
1184 break;
eb1143a3
YK
1185 }
1186}
1187
1188void fm_rds_write_data_pi(struct s610_radio *radio,
1189 struct fm_rds_parser_info *pi)
1190{
1191 u8 buf_ptr[RDS_MEM_MAX_THRESH_PARSER];
1192 u8 i, str_len;
1193 int total_size = 0;
1194 u16 usage;
1195
1196#ifdef USE_RINGBUFF_API
1197 if (ringbuf_bytes_free(&radio->rds_rb) < RDS_MEM_MAX_THRESH_PARSER) {
e16618ee 1198 RDSEBUG(radio, ">>> ringbuff not free, wait..");
eb1143a3
YK
1199 /*ringbuf_reset(&radio->rds_rb);*/
1200 return;
1201 }
1202#else
1203 dev_info(radio->dev, ">>> ringbuff API not used, fail..");
1204 return;
1205#endif /* USE_RINGBUFF_API */
1206
1207 memset(buf_ptr, 0, RDS_MEM_MAX_THRESH_PARSER);
1208
1209 while (pi->rds_event) {
1210 RDSEBUG(radio,
1211 "%s() rds_event[%04X]\n", __func__, pi->rds_event);
1212
1213 if (pi->rds_event & RDS_EVENT_PI_MASK) {
1214 pi->rds_event &= ~RDS_EVENT_PI_MASK;
1215 buf_ptr[total_size] = RDS_EVENT_PI;
1216 buf_ptr[total_size+1] = 2;
1217 buf_ptr[total_size+2] = (u8)(pi->pi_buf[0] & 0xFF);
1218 buf_ptr[total_size+3] = (u8)(pi->pi_buf[0] >> 8);
1219 RDSEBUG(radio,
1220 "[RDS] Enqueue PI data[%02X:%02X:%02X:%02X]. total=%d\n",
1221 buf_ptr[total_size],buf_ptr[total_size+1],buf_ptr[total_size+2],buf_ptr[total_size+3],
1222 total_size+4);
1223
1224 total_size += 4;
1225
1226 } else if (pi->rds_event & RDS_EVENT_AF_MASK) {
1227 pi->rds_event &= ~RDS_EVENT_AF_MASK;
1228 buf_ptr[total_size] = RDS_EVENT_AF;
1229 buf_ptr[total_size+1] = 2;
1230 buf_ptr[total_size+2] = (u8)(pi->af_buf[0] & 0xFF);
1231 buf_ptr[total_size+3] = (u8)(pi->af_buf[0] >> 8);
1232 RDSEBUG(radio,
1233 "[RDS] Enqueue AF data[%02X:%02X:%02X:%02X]. total=%d\n",
1234 buf_ptr[total_size],buf_ptr[total_size+1],buf_ptr[total_size+2],buf_ptr[total_size+3],
1235 total_size+4);
1236
1237 total_size += 4;
1238
1239 } else if (pi->rds_event & RDS_EVENT_PS_MASK) {
1240 pi->rds_event &= ~RDS_EVENT_PS_MASK;
1241 str_len = strlen(pi->ps_candidate);
1242 buf_ptr[total_size] = RDS_EVENT_PS;
1243 buf_ptr[total_size+1] = str_len;
1244
1245 for (i = 0; i < str_len; i++) {
1246 buf_ptr[total_size + i + 2] = pi->ps_candidate[i];
1247 }
1248
1249 total_size += str_len + 2;
1250 RDSEBUG(radio,
1251 "[RDS] Enqueue PS data. total=%d,%d,%d\n", total_size, pi->ps_len + 2, str_len);
1252 } else if (pi->rds_event & RDS_EVENT_RT_MASK) {
1253 pi->rds_event &= ~RDS_EVENT_RT_MASK;
1254 str_len = strlen(pi->rt_candidate);
1255 buf_ptr[total_size] = RDS_EVENT_RT;
1256 buf_ptr[total_size+1] = str_len;
1257
1258 for (i = 0; i < str_len; i++) {
1259 buf_ptr[total_size + i + 2] = pi->rt_candidate[i];
1260 }
1261
1262 total_size += str_len + 2;
1263 RDSEBUG(radio,
1264 "[RDS] Enqueue RT data. total=%d,%d,%d\n", total_size, pi->rt_len + 2, str_len + 2);
1265 } else if (pi->rds_event & RDS_EVENT_ECC_MASK) {
1266 pi->rds_event &= ~RDS_EVENT_ECC_MASK;
1267
1268 buf_ptr[total_size] = RDS_EVENT_ECC;
1269 buf_ptr[total_size+1] = 1;
1270 buf_ptr[total_size+2] = (u8)pi->ecc_buf[0];
1271 RDSEBUG(radio,
1272 "[RDS] Enqueue ECC data[%02d:%02d:%02d]. total=%d\n",
1273 buf_ptr[total_size],buf_ptr[total_size+1],buf_ptr[total_size+2],
1274 total_size+3);
1275
1276 total_size += 3;
1277 } else if (pi->rds_event & RDS_EVENT_RTP_MASK) {
1278 pi->rds_event &= ~RDS_EVENT_RTP_MASK;
1279
1280 buf_ptr[total_size] = RDS_EVENT_RTP;
1281 buf_ptr[total_size+1] = sizeof(struct rtp_info);
1282 memcpy(buf_ptr+total_size+2, &(pi->rtp_data), sizeof(struct rtp_info));
1283 RDSEBUG(radio, "[RDS] Enqueue RTPlus data\n");
1284 RDSEBUG(radio, "[RDS] Toggle:%d, Running:%d, Validated;%d\n", pi->rtp_data.toggle, pi->rtp_data.running, pi->rtp_data.validated);
1285 RDSEBUG(radio, "[%d,%d,%d]\n", pi->rtp_data.tag[0].content_type, pi->rtp_data.tag[0].start_pos, pi->rtp_data.tag[0].len);
1286 RDSEBUG(radio, "[%d,%d,%d]\n", pi->rtp_data.tag[1].content_type, pi->rtp_data.tag[1].start_pos, pi->rtp_data.tag[1].len);
1287
1288 total_size += sizeof(struct rtp_info) + 2;
4e871175
YK
1289 } else if (pi->rds_event & RDS_EVENT_PTY_MASK) {
1290 pi->rds_event &= ~RDS_EVENT_PTY_MASK;
1291
1292 buf_ptr[total_size] = RDS_EVENT_PTY;
1293 buf_ptr[total_size+1] = 1;
1294 buf_ptr[total_size+2] = pi->pty;
1295 RDSEBUG(radio,
1296 "[RDS] Enqueue PTY data[%02X:%02X:%02X]. total=%d\n",
1297 buf_ptr[total_size],buf_ptr[total_size+1],buf_ptr[total_size+2],
1298 total_size+3);
1299
1300 total_size += 3;
eb1143a3
YK
1301 }
1302
1303 if (!pi->rds_event && total_size) {
1304#ifdef USE_RINGBUFF_API
1305 if (!ringbuf_memcpy_into(&radio->rds_rb, buf_ptr, total_size)) {
1306 usage = ringbuf_bytes_used(&radio->rds_rb);
e16618ee 1307 RDSEBUG(radio,
eb1143a3
YK
1308 "%s():>>>RB memcpy into fail! usage:%04d",
1309 __func__, ringbuf_bytes_used(&radio->rds_rb));
1310 if (!usage)
1311 return;
1312 }
1313
1314 usage = ringbuf_bytes_used(&radio->rds_rb);
1315#else
e16618ee 1316 RDSEBUG(radio, ">>> ringbuff API not used, fail..");
eb1143a3
YK
1317#endif /* USE_RINGBUFF_API */
1318
1319 if (atomic_read(&radio->is_rds_new))
1320 return;
1321
1322 fm_set_flag_bits(radio, FLAG_BUF_FUL);
1323 atomic_set(&radio->is_rds_new, 1);
1324 wake_up_interruptible(&radio->core->rds_read_queue);
1325 radio->rds_n_count++;
1326
1327 if (!(radio->rds_n_count%200)) {
1328 fm_update_rssi_work(radio);
e16618ee 1329 RDSEBUG(radio,
eb1143a3
YK
1330 ">>>[FM] RSSI[%03d] NCOUNT[%08d] FIFO_ERR[%08d] USAGE[%04d] SYNCLOSS[%08d]",
1331 radio->low->fm_state.rssi, radio->rds_n_count, radio->rds_fifo_err_cnt,
1332 usage, radio->rds_sync_loss_cnt);
1333 }
1334 }
1335 }
1336}
1337
1338#ifndef USE_RDS_HW_DECODER
1339struct fm_decoded_data {
1340 u16 info;
1341 fm_rds_block_type_enum blk_type;
1342 u8 err_cnt;
1343};
1344
1345void put_bit_to_byte(u8 *fifo, u32 data)
1346{
1347 s8 i, j;
1348 u32 mask = 0x80000000;
1349
1350 for (i = BUF_LEN - 1, j = 0; i >= 0; i--, j++) {
1351 *(fifo + j) = (mask & data) ? 1 : 0;
1352 mask = mask >> 1;
1353 }
1354}
1355
1356u32 get_block_data(u8 *fifo, u32 sp)
1357{
1358 u8 i, j;
1359 u32 data = 0;
1360
1361 data |= *(fifo + (sp++ % 160));
1362
1363 for (i = BLK_LEN-1, j = 0; i > 0; i--, j++) {
1364 data <<= 1;
1365 data |= *(fifo + (sp++ % 160));
1366 }
1367
1368 return data;
1369}
1370
1371u8 find_code_word(u32 *data, fm_rds_block_type_enum b_type, bool seq_lock)
1372{
1373 u16 first13;
1374 u16 second13;
1375 u16 syndrome;
1376
1377 first13 = *data >> 13;
1378 second13 = (*data & 0x1FFF) ^ OFFSET_WORD[b_type];
1379
1380 syndrome = CRC_LUT[(CRC_LUT[first13] << 3) ^ second13];
1381
1382 if (syndrome) {
1383 u32 corrected;
1384 u8 i, j;
1385 u8 maxerr = (b_type == RDS_BLKTYPE_A) ? 2 : sizeof(burstErrorPattern) / sizeof(u8);
1386
1387 for (i = 0; i < maxerr; i++) {
1388 for (j = 0; j <= BLK_LEN - burstErrorLen[i]; j++) {
1389 corrected = *data ^ (burstErrorPattern[i] << j);
1390
1391 first13 = corrected >> 13;
1392 second13 = (corrected & 0x1FFF) ^ OFFSET_WORD[b_type];
1393
1394 syndrome = CRC_LUT[(CRC_LUT[first13] << 3) ^ second13];
1395
1396 if (!syndrome) {
1397 *data = corrected;
1398 return burstErrorLen[i];
1399 }
1400 }
1401 }
1402 } else {
1403 return 0;
1404 }
1405 return 6;
1406}
1407
1408void fm_process_rds_data(struct s610_radio *radio)
1409{
1410 u16 i, j, k, l;
1411 u16 avail_blocks;
1412 u32 fifo_data;
1413 u32 data;
1414 fm_host_rds_errors_enum err_cnt;
1415 u8 min_pos = 0;
1416 u8 min_blk = 0;
1417 u8 min_blk_tmp = 0;
1418 u8 min_pos_sum, min_blk_sum;
1419
1420 static u32 idx;
1421 static u8 fifo[160];
1422 static u32 start_pos;
1423 static u32 end_pos;
1424 static bool fetch_data;
1425 static bool seq_lock;
1426 static bool remains;
1427 static struct fm_decoded_data decoded[BLK_LEN][RDS_NUM_BLOCK_TYPES - 1][RDS_NUM_BLOCK_TYPES - 1];
1428 u32 fifo_status;
1429
1430 fifo_status = fmspeedy_get_reg_work(0xFFF398);
1431 avail_blocks = (((fifo_status >> 8) & 0x3F));
1432 RDSEBUG(radio,"%s(): avail_blocks:%d fifo_status[%08X]",__func__, avail_blocks, fifo_status);
1433
1434 while (avail_blocks) {
1435 /* Fetch the RDS raw data. */
1436 if (fetch_data) {
1437 fifo_data = fmspeedy_get_reg_work(0xFFF3C0);
1438 put_bit_to_byte(fifo + 32 * ((idx++) % 5), fifo_data);
1439 avail_blocks--;
1440 }
1441
1442 switch (fm_rds_get_state(radio)) {
1443 case RDS_STATE_INIT:
1444 fm_rds_change_state(radio, RDS_STATE_HAVE_DATA);
1445 fm_update_rds_sync_status(radio, false);
1446 radio->low->fm_rds_state.error_bits = 0;
1447 radio->low->fm_rds_state.error_blks = 0;
1448
1449 idx = 0;
1450 start_pos = 0;
1451 end_pos = BLK_LEN - 1;
1452 fetch_data = false;
1453 seq_lock = false;
1454 memset(fifo, 0, sizeof(fifo) / sizeof(u8));
1455
1456 case RDS_STATE_HAVE_DATA:
1457 if (idx < 5) {
1458 fifo_data = fmspeedy_get_reg_work(0xFFF3C0);
1459 put_bit_to_byte(fifo + 32 * ((idx++) % 5), fifo_data);
1460 avail_blocks--;
1461
1462 if (idx == 5) {
1463 for (i = 0; i < BLK_LEN; i++) {
1464 for (j = 0; j < RDS_NUM_BLOCK_TYPES - 1; j++) {
1465 start_pos = i;
1466
1467 for (k = 0, l = j; k < RDS_NUM_BLOCK_TYPES - 1; k++) {
1468 data = get_block_data(fifo, start_pos);
1469 err_cnt = find_code_word(&data, l, seq_lock);
1470
1471 decoded[i][j][k].info = data >> 10;
1472 decoded[i][j][k].blk_type = l;
1473 decoded[i][j][k].err_cnt = err_cnt;
1474 start_pos += BLK_LEN;
1475 l = (l + 1) % (RDS_NUM_BLOCK_TYPES - 1);
1476 }
1477 }
1478 }
1479
1480 for (i = 0, min_pos_sum = 0xFF; i < BLK_LEN; i++) {
1481 for (j = 0, min_blk_sum = 0xFF; j < RDS_NUM_BLOCK_TYPES - 1; j++) {
1482 for (k = 0, err_cnt = 0; k < RDS_NUM_BLOCK_TYPES - 1; k++) {
1483 err_cnt += decoded[i][j][k].err_cnt;
1484 }
1485
1486 if (min_blk_sum > err_cnt) {
1487 min_blk_sum = err_cnt;
1488 min_blk_tmp = j;
1489 }
1490 }
1491
1492 if (min_pos_sum > min_blk_sum) {
1493 min_pos_sum = min_blk_sum;
1494 min_pos = i;
1495 min_blk = min_blk_tmp;
1496 }
1497
1498 }
1499
1500 fm_rds_change_state(radio, RDS_STATE_PRE_SYNC);
1501 } else
1502 break;
1503 }
1504
1505 case RDS_STATE_PRE_SYNC:
1506 for (i = 0; i < RDS_NUM_BLOCK_TYPES - 1; i++) {
1507 if (decoded[min_pos][min_blk][i].blk_type == RDS_BLKTYPE_A) {
1508 fm_update_rds_sync_status(radio, TRUE);
1509 }
1510
1511 if (fm_get_rds_sync_status(radio)) {
1512
1513 if (fm_rds_process_block(radio, decoded[min_pos][min_blk][i].info,
1514 decoded[min_pos][min_blk][i].blk_type, decoded[min_pos][min_blk][i].err_cnt)
1515 == HOST_RDS_ERRS_UNCORR) {
1516 fm_rds_update_error_status(radio,
1517 radio->low->fm_state.rds_unsync_uncorr_weight);
1518 } else {
1519 fm_rds_update_error_status(radio, decoded[min_pos][min_blk][i].err_cnt);
1520 }
1521 }
1522 }
1523
1524 start_pos = min_pos + BLK_LEN * 3;
1525 end_pos = start_pos + BLK_LEN - 1;
1526
1527 fm_rds_change_state(radio, (min_blk + 3) % (RDS_NUM_BLOCK_TYPES - 1));
1528 seq_lock = false;
1529 remains = true;
1530
1531 case RDS_STATE_FOUND_BL_A:
1532 case RDS_STATE_FOUND_BL_B:
1533 case RDS_STATE_FOUND_BL_C:
1534 case RDS_STATE_FOUND_BL_D:
1535 if ((end_pos / BUF_LEN != (end_pos + BLK_LEN) / BUF_LEN) && !fetch_data && !remains) {
1536 fetch_data = true;
1537 } else {
1538 if (end_pos + BLK_LEN >= 160 && remains) {
1539 remains = false;
1540 fetch_data = true;
1541 break;
1542 }
1543
1544 start_pos += BLK_LEN;
1545 end_pos += BLK_LEN;
1546
1547 data = get_block_data(fifo, start_pos);
1548 fetch_data = false;
1549
1550 i = (fm_rds_get_state(radio) + 1) % (RDS_NUM_BLOCK_TYPES - 1);
1551 fm_rds_change_state(radio, i);
1552 err_cnt = find_code_word(&data, i, seq_lock);
1553
1554 RDSEBUG(radio,"%s(): data:0x%x, errcnt:%d, gcount:%d", __func__, data, err_cnt, radio->rds_gcnt++);
1555 if (fm_rds_process_block(radio, data >> 10, i, err_cnt) == HOST_RDS_ERRS_UNCORR) {
1556 fm_rds_update_error_status(radio, radio->low->fm_state.rds_unsync_uncorr_weight);
1557 } else {
1558 fm_rds_update_error_status(radio, err_cnt);
1559 }
1560 }
1561 break;
1562
1563 default:
1564 break;
1565 }
1566 }
1567}
1568#endif /*USE_RDS_HW_DECODER*/