Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / media / dvb-frontends / cxd2880 / cxd2880_tnrdmd_dvbt2_mon.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * cxd2880_tnrdmd_dvbt2_mon.c
4  * Sony CXD2880 DVB-T2/T tuner + demodulator driver
5  * DVB-T2 monitor functions
6  *
7  * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
8  */
9
10 #include "cxd2880_tnrdmd_mon.h"
11 #include "cxd2880_tnrdmd_dvbt2.h"
12 #include "cxd2880_tnrdmd_dvbt2_mon.h"
13
14 #include <media/dvb_math.h>
15
16 static const int ref_dbm_1000[4][8] = {
17         {-96000, -95000, -94000, -93000, -92000, -92000, -98000, -97000},
18         {-91000, -89000, -88000, -87000, -86000, -86000, -93000, -92000},
19         {-86000, -85000, -83000, -82000, -81000, -80000, -89000, -88000},
20         {-82000, -80000, -78000, -76000, -75000, -74000, -86000, -84000},
21 };
22
23 int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
24                                        *tnr_dmd, u8 *sync_stat,
25                                        u8 *ts_lock_stat,
26                                        u8 *unlock_detected)
27 {
28         u8 data;
29         int ret;
30
31         if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected)
32                 return -EINVAL;
33
34         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
35                 return -EINVAL;
36
37         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
38                 return -EINVAL;
39
40         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
41                                      CXD2880_IO_TGT_DMD,
42                                      0x00, 0x0b);
43         if (ret)
44                 return ret;
45
46         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
47                                      CXD2880_IO_TGT_DMD,
48                                      0x10, &data, sizeof(data));
49         if (ret)
50                 return ret;
51
52         *sync_stat = data & 0x07;
53         *ts_lock_stat = ((data & 0x20) ? 1 : 0);
54         *unlock_detected = ((data & 0x10) ? 1 : 0);
55
56         if (*sync_stat == 0x07)
57                 return -EAGAIN;
58
59         return 0;
60 }
61
62 int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
63                                            *tnr_dmd,
64                                            u8 *sync_stat,
65                                            u8 *unlock_detected)
66 {
67         u8 ts_lock_stat = 0;
68
69         if (!tnr_dmd || !sync_stat || !unlock_detected)
70                 return -EINVAL;
71
72         if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
73                 return -EINVAL;
74
75         return cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub,
76                                                   sync_stat,
77                                                   &ts_lock_stat,
78                                                   unlock_detected);
79 }
80
81 int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
82                                             *tnr_dmd, int *offset)
83 {
84         u8 data[4];
85         u32 ctl_val = 0;
86         u8 sync_state = 0;
87         u8 ts_lock = 0;
88         u8 unlock_detected = 0;
89         int ret;
90
91         if (!tnr_dmd || !offset)
92                 return -EINVAL;
93
94         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
95                 return -EINVAL;
96
97         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
98                 return -EINVAL;
99
100         ret = slvt_freeze_reg(tnr_dmd);
101         if (ret)
102                 return ret;
103
104         ret =
105             cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
106                                                &ts_lock,
107                                                &unlock_detected);
108         if (ret) {
109                 slvt_unfreeze_reg(tnr_dmd);
110                 return ret;
111         }
112
113         if (sync_state != 6) {
114                 slvt_unfreeze_reg(tnr_dmd);
115                 return -EAGAIN;
116         }
117
118         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
119                                      CXD2880_IO_TGT_DMD,
120                                      0x00, 0x0b);
121         if (ret) {
122                 slvt_unfreeze_reg(tnr_dmd);
123                 return ret;
124         }
125
126         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
127                                      CXD2880_IO_TGT_DMD,
128                                      0x30, data, sizeof(data));
129         if (ret) {
130                 slvt_unfreeze_reg(tnr_dmd);
131                 return ret;
132         }
133
134         slvt_unfreeze_reg(tnr_dmd);
135
136         ctl_val =
137             ((data[0] & 0x0f) << 24) | (data[1] << 16) | (data[2] << 8)
138             | (data[3]);
139         *offset = cxd2880_convert2s_complement(ctl_val, 28);
140
141         switch (tnr_dmd->bandwidth) {
142         case CXD2880_DTV_BW_1_7_MHZ:
143                 *offset = -1 * ((*offset) / 582);
144                 break;
145         case CXD2880_DTV_BW_5_MHZ:
146         case CXD2880_DTV_BW_6_MHZ:
147         case CXD2880_DTV_BW_7_MHZ:
148         case CXD2880_DTV_BW_8_MHZ:
149                 *offset = -1 * ((*offset) * tnr_dmd->bandwidth / 940);
150                 break;
151         default:
152                 return -EINVAL;
153         }
154
155         return 0;
156 }
157
158 int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
159                                                 cxd2880_tnrdmd
160                                                 *tnr_dmd,
161                                                 int *offset)
162 {
163         if (!tnr_dmd || !offset)
164                 return -EINVAL;
165
166         if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
167                 return -EINVAL;
168
169         return cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub,
170                                                        offset);
171 }
172
173 int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
174                                     struct cxd2880_dvbt2_l1pre
175                                     *l1_pre)
176 {
177         u8 data[37];
178         u8 sync_state = 0;
179         u8 ts_lock = 0;
180         u8 unlock_detected = 0;
181         u8 version = 0;
182         enum cxd2880_dvbt2_profile profile;
183         int ret;
184
185         if (!tnr_dmd || !l1_pre)
186                 return -EINVAL;
187
188         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
189                 return -EINVAL;
190
191         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
192                 return -EINVAL;
193
194         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
195                 return -EINVAL;
196
197         ret = slvt_freeze_reg(tnr_dmd);
198         if (ret)
199                 return ret;
200
201         ret =
202             cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
203                                                &ts_lock,
204                                                &unlock_detected);
205         if (ret) {
206                 slvt_unfreeze_reg(tnr_dmd);
207                 return ret;
208         }
209
210         if (sync_state < 5) {
211                 if (tnr_dmd->diver_mode ==
212                     CXD2880_TNRDMD_DIVERMODE_MAIN) {
213                         ret =
214                             cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
215                             (tnr_dmd, &sync_state, &unlock_detected);
216                         if (ret) {
217                                 slvt_unfreeze_reg(tnr_dmd);
218                                 return ret;
219                         }
220
221                         if (sync_state < 5) {
222                                 slvt_unfreeze_reg(tnr_dmd);
223                                 return -EAGAIN;
224                         }
225                 } else {
226                         slvt_unfreeze_reg(tnr_dmd);
227                         return -EAGAIN;
228                 }
229         }
230
231         ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile);
232         if (ret) {
233                 slvt_unfreeze_reg(tnr_dmd);
234                 return ret;
235         }
236
237         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
238                                      CXD2880_IO_TGT_DMD,
239                                      0x00, 0x0b);
240         if (ret) {
241                 slvt_unfreeze_reg(tnr_dmd);
242                 return ret;
243         }
244
245         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
246                                      CXD2880_IO_TGT_DMD,
247                                      0x61, data, sizeof(data));
248         if (ret) {
249                 slvt_unfreeze_reg(tnr_dmd);
250                 return ret;
251         }
252         slvt_unfreeze_reg(tnr_dmd);
253
254         l1_pre->type = (enum cxd2880_dvbt2_l1pre_type)data[0];
255         l1_pre->bw_ext = data[1] & 0x01;
256         l1_pre->s1 = (enum cxd2880_dvbt2_s1)(data[2] & 0x07);
257         l1_pre->s2 = data[3] & 0x0f;
258         l1_pre->l1_rep = data[4] & 0x01;
259         l1_pre->gi = (enum cxd2880_dvbt2_guard)(data[5] & 0x07);
260         l1_pre->papr = (enum cxd2880_dvbt2_papr)(data[6] & 0x0f);
261         l1_pre->mod =
262             (enum cxd2880_dvbt2_l1post_constell)(data[7] & 0x0f);
263         l1_pre->cr = (enum cxd2880_dvbt2_l1post_cr)(data[8] & 0x03);
264         l1_pre->fec =
265             (enum cxd2880_dvbt2_l1post_fec_type)(data[9] & 0x03);
266         l1_pre->l1_post_size = (data[10] & 0x03) << 16;
267         l1_pre->l1_post_size |= (data[11]) << 8;
268         l1_pre->l1_post_size |= (data[12]);
269         l1_pre->l1_post_info_size = (data[13] & 0x03) << 16;
270         l1_pre->l1_post_info_size |= (data[14]) << 8;
271         l1_pre->l1_post_info_size |= (data[15]);
272         l1_pre->pp = (enum cxd2880_dvbt2_pp)(data[16] & 0x0f);
273         l1_pre->tx_id_availability = data[17];
274         l1_pre->cell_id = (data[18] << 8);
275         l1_pre->cell_id |= (data[19]);
276         l1_pre->network_id = (data[20] << 8);
277         l1_pre->network_id |= (data[21]);
278         l1_pre->sys_id = (data[22] << 8);
279         l1_pre->sys_id |= (data[23]);
280         l1_pre->num_frames = data[24];
281         l1_pre->num_symbols = (data[25] & 0x0f) << 8;
282         l1_pre->num_symbols |= data[26];
283         l1_pre->regen = data[27] & 0x07;
284         l1_pre->post_ext = data[28] & 0x01;
285         l1_pre->num_rf_freqs = data[29] & 0x07;
286         l1_pre->rf_idx = data[30] & 0x07;
287         version = (data[31] & 0x03) << 2;
288         version |= (data[32] & 0xc0) >> 6;
289         l1_pre->t2_version = (enum cxd2880_dvbt2_version)version;
290         l1_pre->l1_post_scrambled = (data[32] & 0x20) >> 5;
291         l1_pre->t2_base_lite = (data[32] & 0x10) >> 4;
292         l1_pre->crc32 = (data[33] << 24);
293         l1_pre->crc32 |= (data[34] << 16);
294         l1_pre->crc32 |= (data[35] << 8);
295         l1_pre->crc32 |= data[36];
296
297         if (profile == CXD2880_DVBT2_PROFILE_BASE) {
298                 switch ((l1_pre->s2 >> 1)) {
299                 case CXD2880_DVBT2_BASE_S2_M1K_G_ANY:
300                         l1_pre->fft_mode = CXD2880_DVBT2_M1K;
301                         break;
302                 case CXD2880_DVBT2_BASE_S2_M2K_G_ANY:
303                         l1_pre->fft_mode = CXD2880_DVBT2_M2K;
304                         break;
305                 case CXD2880_DVBT2_BASE_S2_M4K_G_ANY:
306                         l1_pre->fft_mode = CXD2880_DVBT2_M4K;
307                         break;
308                 case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT:
309                 case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2:
310                         l1_pre->fft_mode = CXD2880_DVBT2_M8K;
311                         break;
312                 case CXD2880_DVBT2_BASE_S2_M16K_G_ANY:
313                         l1_pre->fft_mode = CXD2880_DVBT2_M16K;
314                         break;
315                 case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT:
316                 case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2:
317                         l1_pre->fft_mode = CXD2880_DVBT2_M32K;
318                         break;
319                 default:
320                         return -EAGAIN;
321                 }
322         } else if (profile == CXD2880_DVBT2_PROFILE_LITE) {
323                 switch ((l1_pre->s2 >> 1)) {
324                 case CXD2880_DVBT2_LITE_S2_M2K_G_ANY:
325                         l1_pre->fft_mode = CXD2880_DVBT2_M2K;
326                         break;
327                 case CXD2880_DVBT2_LITE_S2_M4K_G_ANY:
328                         l1_pre->fft_mode = CXD2880_DVBT2_M4K;
329                         break;
330                 case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT:
331                 case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2:
332                         l1_pre->fft_mode = CXD2880_DVBT2_M8K;
333                         break;
334                 case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT:
335                 case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2:
336                         l1_pre->fft_mode = CXD2880_DVBT2_M16K;
337                         break;
338                 default:
339                         return -EAGAIN;
340                 }
341         } else {
342                 return -EAGAIN;
343         }
344
345         l1_pre->mixed = l1_pre->s2 & 0x01;
346
347         return ret;
348 }
349
350 int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
351                                      *tnr_dmd,
352                                      enum cxd2880_dvbt2_version
353                                      *ver)
354 {
355         u8 data[2];
356         u8 sync_state = 0;
357         u8 ts_lock = 0;
358         u8 unlock_detected = 0;
359         u8 version = 0;
360         int ret;
361
362         if (!tnr_dmd || !ver)
363                 return -EINVAL;
364
365         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
366                 return -EINVAL;
367
368         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
369                 return -EINVAL;
370
371         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
372                 return -EINVAL;
373
374         ret = slvt_freeze_reg(tnr_dmd);
375         if (ret)
376                 return ret;
377
378         ret =
379             cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
380                                                &ts_lock,
381                                                &unlock_detected);
382         if (ret) {
383                 slvt_unfreeze_reg(tnr_dmd);
384                 return ret;
385         }
386
387         if (sync_state < 5) {
388                 if (tnr_dmd->diver_mode ==
389                     CXD2880_TNRDMD_DIVERMODE_MAIN) {
390                         ret =
391                             cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
392                             (tnr_dmd, &sync_state, &unlock_detected);
393                         if (ret) {
394                                 slvt_unfreeze_reg(tnr_dmd);
395                                 return ret;
396                         }
397
398                         if (sync_state < 5) {
399                                 slvt_unfreeze_reg(tnr_dmd);
400                                 return -EAGAIN;
401                         }
402                 } else {
403                         slvt_unfreeze_reg(tnr_dmd);
404                         return -EAGAIN;
405                 }
406         }
407
408         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
409                                      CXD2880_IO_TGT_DMD,
410                                      0x00, 0x0b);
411         if (ret) {
412                 slvt_unfreeze_reg(tnr_dmd);
413                 return ret;
414         }
415
416         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
417                                      CXD2880_IO_TGT_DMD,
418                                      0x80, data, sizeof(data));
419         if (ret) {
420                 slvt_unfreeze_reg(tnr_dmd);
421                 return ret;
422         }
423
424         slvt_unfreeze_reg(tnr_dmd);
425
426         version = ((data[0] & 0x03) << 2);
427         version |= ((data[1] & 0xc0) >> 6);
428         *ver = (enum cxd2880_dvbt2_version)version;
429
430         return ret;
431 }
432
433 int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
434                                   struct cxd2880_dvbt2_ofdm *ofdm)
435 {
436         u8 data[5];
437         u8 sync_state = 0;
438         u8 ts_lock = 0;
439         u8 unlock_detected = 0;
440         int ret;
441
442         if (!tnr_dmd || !ofdm)
443                 return -EINVAL;
444
445         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
446                 return -EINVAL;
447
448         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
449                 return -EINVAL;
450
451         ret = slvt_freeze_reg(tnr_dmd);
452         if (ret)
453                 return ret;
454
455         ret =
456             cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
457                                                &ts_lock,
458                                                &unlock_detected);
459         if (ret) {
460                 slvt_unfreeze_reg(tnr_dmd);
461                 return ret;
462         }
463
464         if (sync_state != 6) {
465                 slvt_unfreeze_reg(tnr_dmd);
466
467                 ret = -EAGAIN;
468
469                 if (tnr_dmd->diver_mode ==
470                     CXD2880_TNRDMD_DIVERMODE_MAIN)
471                         ret =
472                             cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd->diver_sub,
473                                                           ofdm);
474
475                 return ret;
476         }
477
478         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
479                                      CXD2880_IO_TGT_DMD,
480                                      0x00, 0x0b);
481         if (ret) {
482                 slvt_unfreeze_reg(tnr_dmd);
483                 return ret;
484         }
485
486         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
487                                      CXD2880_IO_TGT_DMD,
488                                      0x1d, data, sizeof(data));
489         if (ret) {
490                 slvt_unfreeze_reg(tnr_dmd);
491                 return ret;
492         }
493
494         slvt_unfreeze_reg(tnr_dmd);
495
496         ofdm->mixed = ((data[0] & 0x20) ? 1 : 0);
497         ofdm->is_miso = ((data[0] & 0x10) >> 4);
498         ofdm->mode = (enum cxd2880_dvbt2_mode)(data[0] & 0x07);
499         ofdm->gi = (enum cxd2880_dvbt2_guard)((data[1] & 0x70) >> 4);
500         ofdm->pp = (enum cxd2880_dvbt2_pp)(data[1] & 0x07);
501         ofdm->bw_ext = (data[2] & 0x10) >> 4;
502         ofdm->papr = (enum cxd2880_dvbt2_papr)(data[2] & 0x0f);
503         ofdm->num_symbols = (data[3] << 8) | data[4];
504
505         return 0;
506 }
507
508 int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
509                                        *tnr_dmd, u8 *plp_ids,
510                                        u8 *num_plps)
511 {
512         u8 l1_post_ok = 0;
513         int ret;
514
515         if (!tnr_dmd || !num_plps)
516                 return -EINVAL;
517
518         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
519                 return -EINVAL;
520
521         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
522                 return -EINVAL;
523
524         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
525                 return -EINVAL;
526
527         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
528                                      CXD2880_IO_TGT_DMD,
529                                      0x00, 0x0b);
530         if (ret)
531                 return ret;
532
533         ret = slvt_freeze_reg(tnr_dmd);
534         if (ret)
535                 return ret;
536
537         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
538                                      CXD2880_IO_TGT_DMD,
539                                      0x86, &l1_post_ok, 1);
540         if (ret) {
541                 slvt_unfreeze_reg(tnr_dmd);
542                 return ret;
543         }
544
545         if (!(l1_post_ok & 0x01)) {
546                 slvt_unfreeze_reg(tnr_dmd);
547                 return -EAGAIN;
548         }
549
550         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
551                                      CXD2880_IO_TGT_DMD,
552                                      0xc1, num_plps, 1);
553         if (ret) {
554                 slvt_unfreeze_reg(tnr_dmd);
555                 return ret;
556         }
557
558         if (*num_plps == 0) {
559                 slvt_unfreeze_reg(tnr_dmd);
560                 return -EINVAL;
561         }
562
563         if (!plp_ids) {
564                 slvt_unfreeze_reg(tnr_dmd);
565                 return 0;
566         }
567
568         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
569                                      CXD2880_IO_TGT_DMD,
570                                      0xc2,
571                                      plp_ids,
572                                      ((*num_plps > 62) ?
573                                      62 : *num_plps));
574         if (ret) {
575                 slvt_unfreeze_reg(tnr_dmd);
576                 return ret;
577         }
578
579         if (*num_plps > 62) {
580                 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
581                                              CXD2880_IO_TGT_DMD,
582                                              0x00, 0x0c);
583                 if (ret) {
584                         slvt_unfreeze_reg(tnr_dmd);
585                         return ret;
586                 }
587
588                 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
589                                              CXD2880_IO_TGT_DMD,
590                                              0x10, plp_ids + 62,
591                                              *num_plps - 62);
592                 if (ret) {
593                         slvt_unfreeze_reg(tnr_dmd);
594                         return ret;
595                 }
596         }
597
598         slvt_unfreeze_reg(tnr_dmd);
599
600         return 0;
601 }
602
603 int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
604                                         *tnr_dmd,
605                                         enum
606                                         cxd2880_dvbt2_plp_btype
607                                         type,
608                                         struct cxd2880_dvbt2_plp
609                                         *plp_info)
610 {
611         u8 data[20];
612         u8 addr = 0;
613         u8 index = 0;
614         u8 l1_post_ok = 0;
615         int ret;
616
617         if (!tnr_dmd || !plp_info)
618                 return -EINVAL;
619
620         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
621                 return -EINVAL;
622
623         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
624                 return -EINVAL;
625
626         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
627                 return -EINVAL;
628
629         ret = slvt_freeze_reg(tnr_dmd);
630         if (ret)
631                 return ret;
632
633         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
634                                      CXD2880_IO_TGT_DMD,
635                                      0x00, 0x0b);
636         if (ret) {
637                 slvt_unfreeze_reg(tnr_dmd);
638                 return ret;
639         }
640
641         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
642                                      CXD2880_IO_TGT_DMD,
643                                      0x86, &l1_post_ok, 1);
644         if (ret) {
645                 slvt_unfreeze_reg(tnr_dmd);
646                 return ret;
647         }
648
649         if (!l1_post_ok) {
650                 slvt_unfreeze_reg(tnr_dmd);
651                 return -EAGAIN;
652         }
653
654         if (type == CXD2880_DVBT2_PLP_COMMON)
655                 addr = 0xa9;
656         else
657                 addr = 0x96;
658
659         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
660                                      CXD2880_IO_TGT_DMD,
661                                      addr, data, sizeof(data));
662         if (ret) {
663                 slvt_unfreeze_reg(tnr_dmd);
664                 return ret;
665         }
666
667         slvt_unfreeze_reg(tnr_dmd);
668
669         if (type == CXD2880_DVBT2_PLP_COMMON && !data[13])
670                 return -EAGAIN;
671
672         plp_info->id = data[index++];
673         plp_info->type =
674             (enum cxd2880_dvbt2_plp_type)(data[index++] & 0x07);
675         plp_info->payload =
676             (enum cxd2880_dvbt2_plp_payload)(data[index++] & 0x1f);
677         plp_info->ff = data[index++] & 0x01;
678         plp_info->first_rf_idx = data[index++] & 0x07;
679         plp_info->first_frm_idx = data[index++];
680         plp_info->group_id = data[index++];
681         plp_info->plp_cr =
682             (enum cxd2880_dvbt2_plp_code_rate)(data[index++] & 0x07);
683         plp_info->constell =
684             (enum cxd2880_dvbt2_plp_constell)(data[index++] & 0x07);
685         plp_info->rot = data[index++] & 0x01;
686         plp_info->fec =
687             (enum cxd2880_dvbt2_plp_fec)(data[index++] & 0x03);
688         plp_info->num_blocks_max = (data[index++] & 0x03) << 8;
689         plp_info->num_blocks_max |= data[index++];
690         plp_info->frm_int = data[index++];
691         plp_info->til_len = data[index++];
692         plp_info->til_type = data[index++] & 0x01;
693
694         plp_info->in_band_a_flag = data[index++] & 0x01;
695         plp_info->rsvd = data[index++] << 8;
696         plp_info->rsvd |= data[index++];
697
698         plp_info->in_band_b_flag =
699             (plp_info->rsvd & 0x8000) >> 15;
700         plp_info->plp_mode =
701             (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000c) >> 2);
702         plp_info->static_flag = (plp_info->rsvd & 0x0002) >> 1;
703         plp_info->static_padding_flag = plp_info->rsvd & 0x0001;
704         plp_info->rsvd = (plp_info->rsvd & 0x7ff0) >> 4;
705
706         return 0;
707 }
708
709 int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
710                                             *tnr_dmd,
711                                             u8 *plp_error)
712 {
713         u8 data;
714         int ret;
715
716         if (!tnr_dmd || !plp_error)
717                 return -EINVAL;
718
719         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
720                 return -EINVAL;
721
722         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
723                 return -EINVAL;
724
725         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
726                 return -EINVAL;
727
728         ret = slvt_freeze_reg(tnr_dmd);
729         if (ret)
730                 return ret;
731
732         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
733                                      CXD2880_IO_TGT_DMD,
734                                      0x00, 0x0b);
735         if (ret) {
736                 slvt_unfreeze_reg(tnr_dmd);
737                 return ret;
738         }
739
740         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
741                                      CXD2880_IO_TGT_DMD,
742                                      0x86, &data, 1);
743         if (ret) {
744                 slvt_unfreeze_reg(tnr_dmd);
745                 return ret;
746         }
747
748         if ((data & 0x01) == 0x00) {
749                 slvt_unfreeze_reg(tnr_dmd);
750                 return -EAGAIN;
751         }
752
753         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
754                                      CXD2880_IO_TGT_DMD,
755                                      0xc0, &data, 1);
756         if (ret) {
757                 slvt_unfreeze_reg(tnr_dmd);
758                 return ret;
759         }
760
761         slvt_unfreeze_reg(tnr_dmd);
762
763         *plp_error = data & 0x01;
764
765         return 0;
766 }
767
768 int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
769                                        *tnr_dmd, u8 *l1_change)
770 {
771         u8 data;
772         u8 sync_state = 0;
773         u8 ts_lock = 0;
774         u8 unlock_detected = 0;
775         int ret;
776
777         if (!tnr_dmd || !l1_change)
778                 return -EINVAL;
779
780         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
781                 return -EINVAL;
782
783         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
784                 return -EINVAL;
785
786         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
787                 return -EINVAL;
788
789         ret = slvt_freeze_reg(tnr_dmd);
790         if (ret)
791                 return ret;
792
793         ret =
794             cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
795                                                &ts_lock,
796                                                &unlock_detected);
797         if (ret) {
798                 slvt_unfreeze_reg(tnr_dmd);
799                 return ret;
800         }
801
802         if (sync_state < 5) {
803                 if (tnr_dmd->diver_mode ==
804                     CXD2880_TNRDMD_DIVERMODE_MAIN) {
805                         ret =
806                             cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
807                             (tnr_dmd, &sync_state, &unlock_detected);
808                         if (ret) {
809                                 slvt_unfreeze_reg(tnr_dmd);
810                                 return ret;
811                         }
812
813                         if (sync_state < 5) {
814                                 slvt_unfreeze_reg(tnr_dmd);
815                                 return -EAGAIN;
816                         }
817                 } else {
818                         slvt_unfreeze_reg(tnr_dmd);
819                         return -EAGAIN;
820                 }
821         }
822
823         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
824                                      CXD2880_IO_TGT_DMD,
825                                      0x00, 0x0b);
826         if (ret) {
827                 slvt_unfreeze_reg(tnr_dmd);
828                 return ret;
829         }
830
831         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
832                                      CXD2880_IO_TGT_DMD,
833                                      0x5f, &data, sizeof(data));
834         if (ret) {
835                 slvt_unfreeze_reg(tnr_dmd);
836                 return ret;
837         }
838
839         *l1_change = data & 0x01;
840         if (*l1_change) {
841                 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
842                                              CXD2880_IO_TGT_DMD,
843                                              0x00, 0x22);
844                 if (ret) {
845                         slvt_unfreeze_reg(tnr_dmd);
846                         return ret;
847                 }
848
849                 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
850                                              CXD2880_IO_TGT_DMD,
851                                              0x16, 0x01);
852                 if (ret) {
853                         slvt_unfreeze_reg(tnr_dmd);
854                         return ret;
855                 }
856         }
857         slvt_unfreeze_reg(tnr_dmd);
858
859         return 0;
860 }
861
862 int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
863                                      *tnr_dmd,
864                                      struct cxd2880_dvbt2_l1post
865                                      *l1_post)
866 {
867         u8 data[16];
868         int ret;
869
870         if (!tnr_dmd || !l1_post)
871                 return -EINVAL;
872
873         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
874                 return -EINVAL;
875
876         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
877                 return -EINVAL;
878
879         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
880                 return -EINVAL;
881
882         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
883                                      CXD2880_IO_TGT_DMD,
884                                      0x00, 0x0b);
885         if (ret)
886                 return ret;
887
888         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
889                                      CXD2880_IO_TGT_DMD,
890                                      0x86, data, sizeof(data));
891         if (ret)
892                 return ret;
893
894         if (!(data[0] & 0x01))
895                 return -EAGAIN;
896
897         l1_post->sub_slices_per_frame = (data[1] & 0x7f) << 8;
898         l1_post->sub_slices_per_frame |= data[2];
899         l1_post->num_plps = data[3];
900         l1_post->num_aux = data[4] & 0x0f;
901         l1_post->aux_cfg_rfu = data[5];
902         l1_post->rf_idx = data[6] & 0x07;
903         l1_post->freq = data[7] << 24;
904         l1_post->freq |= data[8] << 16;
905         l1_post->freq |= data[9] << 8;
906         l1_post->freq |= data[10];
907         l1_post->fef_type = data[11] & 0x0f;
908         l1_post->fef_length = data[12] << 16;
909         l1_post->fef_length |= data[13] << 8;
910         l1_post->fef_length |= data[14];
911         l1_post->fef_intvl = data[15];
912
913         return 0;
914 }
915
916 int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
917                                       *tnr_dmd,
918                                       enum cxd2880_dvbt2_plp_btype
919                                       type,
920                                       struct cxd2880_dvbt2_bbheader
921                                       *bbheader)
922 {
923         u8 sync_state = 0;
924         u8 ts_lock = 0;
925         u8 unlock_detected = 0;
926         u8 data[14];
927         u8 addr = 0;
928         int ret;
929
930         if (!tnr_dmd || !bbheader)
931                 return -EINVAL;
932
933         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
934                 return -EINVAL;
935
936         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
937                 return -EINVAL;
938
939         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
940                 return -EINVAL;
941
942         ret = slvt_freeze_reg(tnr_dmd);
943         if (ret)
944                 return ret;
945
946         ret =
947             cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
948                                                        &ts_lock,
949                                                        &unlock_detected);
950         if (ret) {
951                 slvt_unfreeze_reg(tnr_dmd);
952                 return ret;
953         }
954
955         if (!ts_lock) {
956                 slvt_unfreeze_reg(tnr_dmd);
957                 return -EAGAIN;
958         }
959
960         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
961                                      CXD2880_IO_TGT_DMD,
962                                      0x00, 0x0b);
963         if (ret) {
964                 slvt_unfreeze_reg(tnr_dmd);
965                 return ret;
966         }
967
968         if (type == CXD2880_DVBT2_PLP_COMMON) {
969                 u8 l1_post_ok;
970                 u8 data;
971
972                 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
973                                              CXD2880_IO_TGT_DMD,
974                                              0x86, &l1_post_ok, 1);
975                 if (ret) {
976                         slvt_unfreeze_reg(tnr_dmd);
977                         return ret;
978                 }
979
980                 if (!(l1_post_ok & 0x01)) {
981                         slvt_unfreeze_reg(tnr_dmd);
982                         return -EAGAIN;
983                 }
984
985                 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
986                                              CXD2880_IO_TGT_DMD,
987                                              0xb6, &data, 1);
988                 if (ret) {
989                         slvt_unfreeze_reg(tnr_dmd);
990                         return ret;
991                 }
992
993                 if (data == 0) {
994                         slvt_unfreeze_reg(tnr_dmd);
995                         return -EAGAIN;
996                 }
997         }
998
999         if (type == CXD2880_DVBT2_PLP_COMMON)
1000                 addr = 0x51;
1001         else
1002                 addr = 0x42;
1003
1004         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1005                                      CXD2880_IO_TGT_DMD,
1006                                      addr, data, sizeof(data));
1007         if (ret) {
1008                 slvt_unfreeze_reg(tnr_dmd);
1009                 return ret;
1010         }
1011
1012         slvt_unfreeze_reg(tnr_dmd);
1013
1014         bbheader->stream_input =
1015             (enum cxd2880_dvbt2_stream)((data[0] >> 6) & 0x03);
1016         bbheader->is_single_input_stream = (data[0] >> 5) & 0x01;
1017         bbheader->is_constant_coding_modulation =
1018             (data[0] >> 4) & 0x01;
1019         bbheader->issy_indicator = (data[0] >> 3) & 0x01;
1020         bbheader->null_packet_deletion = (data[0] >> 2) & 0x01;
1021         bbheader->ext = data[0] & 0x03;
1022
1023         bbheader->input_stream_identifier = data[1];
1024         bbheader->plp_mode =
1025             (data[3] & 0x01) ? CXD2880_DVBT2_PLP_MODE_HEM :
1026             CXD2880_DVBT2_PLP_MODE_NM;
1027         bbheader->data_field_length = (data[4] << 8) | data[5];
1028
1029         if (bbheader->plp_mode == CXD2880_DVBT2_PLP_MODE_NM) {
1030                 bbheader->user_packet_length =
1031                     (data[6] << 8) | data[7];
1032                 bbheader->sync_byte = data[8];
1033                 bbheader->issy = 0;
1034         } else {
1035                 bbheader->user_packet_length = 0;
1036                 bbheader->sync_byte = 0;
1037                 bbheader->issy =
1038                     (data[11] << 16) | (data[12] << 8) | data[13];
1039         }
1040
1041         return 0;
1042 }
1043
1044 int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd
1045                                               *tnr_dmd,
1046                                               enum
1047                                               cxd2880_dvbt2_plp_btype
1048                                               type,
1049                                               u32 *ts_rate_bps)
1050 {
1051         u8 sync_state = 0;
1052         u8 ts_lock = 0;
1053         u8 unlock_detected = 0;
1054         u8 l1_post_ok = 0;
1055         u8 data[4];
1056         u8 addr = 0;
1057
1058         int ret;
1059
1060         if (!tnr_dmd || !ts_rate_bps)
1061                 return -EINVAL;
1062
1063         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1064                 return -EINVAL;
1065
1066         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1067                 return -EINVAL;
1068
1069         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1070                 return -EINVAL;
1071
1072         ret = slvt_freeze_reg(tnr_dmd);
1073         if (ret)
1074                 return ret;
1075
1076         ret =
1077             cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
1078                                                &ts_lock,
1079                                                &unlock_detected);
1080         if (ret) {
1081                 slvt_unfreeze_reg(tnr_dmd);
1082                 return ret;
1083         }
1084
1085         if (!ts_lock) {
1086                 slvt_unfreeze_reg(tnr_dmd);
1087                 return -EAGAIN;
1088         }
1089
1090         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1091                                      CXD2880_IO_TGT_DMD,
1092                                      0x00, 0x0b);
1093         if (ret) {
1094                 slvt_unfreeze_reg(tnr_dmd);
1095                 return ret;
1096         }
1097
1098         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1099                                      CXD2880_IO_TGT_DMD,
1100                                      0x86, &l1_post_ok, 1);
1101         if (ret) {
1102                 slvt_unfreeze_reg(tnr_dmd);
1103                 return ret;
1104         }
1105
1106         if (!(l1_post_ok & 0x01)) {
1107                 slvt_unfreeze_reg(tnr_dmd);
1108                 return -EAGAIN;
1109         }
1110
1111         if (type == CXD2880_DVBT2_PLP_COMMON)
1112                 addr = 0xba;
1113         else
1114                 addr = 0xa7;
1115
1116         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1117                                      CXD2880_IO_TGT_DMD,
1118                                      addr, &data[0], 1);
1119         if (ret) {
1120                 slvt_unfreeze_reg(tnr_dmd);
1121                 return ret;
1122         }
1123
1124         if ((data[0] & 0x80) == 0x00) {
1125                 slvt_unfreeze_reg(tnr_dmd);
1126                 return -EAGAIN;
1127         }
1128
1129         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1130                                      CXD2880_IO_TGT_DMD,
1131                                      0x00, 0x25);
1132         if (ret) {
1133                 slvt_unfreeze_reg(tnr_dmd);
1134                 return ret;
1135         }
1136
1137         if (type == CXD2880_DVBT2_PLP_COMMON)
1138                 addr = 0xa6;
1139         else
1140                 addr = 0xaa;
1141
1142         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1143                                      CXD2880_IO_TGT_DMD,
1144                                      addr, &data[0], 4);
1145         if (ret) {
1146                 slvt_unfreeze_reg(tnr_dmd);
1147                 return ret;
1148         }
1149
1150         *ts_rate_bps = ((data[0] & 0x07) << 24) | (data[1] << 16) |
1151                        (data[2] << 8) | data[3];
1152
1153         return 0;
1154 }
1155
1156 int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd
1157                                             *tnr_dmd,
1158                                             enum
1159                                             cxd2880_tnrdmd_spectrum_sense
1160                                             *sense)
1161 {
1162         u8 sync_state = 0;
1163         u8 ts_lock = 0;
1164         u8 early_unlock = 0;
1165         u8 data = 0;
1166         int ret;
1167
1168         if (!tnr_dmd || !sense)
1169                 return -EINVAL;
1170
1171         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1172                 return -EINVAL;
1173
1174         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1175                 return -EINVAL;
1176
1177         ret = slvt_freeze_reg(tnr_dmd);
1178         if (ret)
1179                 return ret;
1180
1181         ret =
1182             cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, &ts_lock,
1183                                                &early_unlock);
1184         if (ret) {
1185                 slvt_unfreeze_reg(tnr_dmd);
1186                 return ret;
1187         }
1188
1189         if (sync_state != 6) {
1190                 slvt_unfreeze_reg(tnr_dmd);
1191
1192                 ret = -EAGAIN;
1193
1194                 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
1195                         ret =
1196                             cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(tnr_dmd->diver_sub,
1197                                                                     sense);
1198
1199                 return ret;
1200         }
1201
1202         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1203                                      CXD2880_IO_TGT_DMD,
1204                                      0x00, 0x0b);
1205         if (ret) {
1206                 slvt_unfreeze_reg(tnr_dmd);
1207                 return ret;
1208         }
1209
1210         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1211                                      CXD2880_IO_TGT_DMD,
1212                                      0x2f, &data, sizeof(data));
1213         if (ret) {
1214                 slvt_unfreeze_reg(tnr_dmd);
1215                 return ret;
1216         }
1217
1218         slvt_unfreeze_reg(tnr_dmd);
1219
1220         *sense =
1221             (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
1222             CXD2880_TNRDMD_SPECTRUM_NORMAL;
1223
1224         return 0;
1225 }
1226
1227 static int dvbt2_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
1228                               u16 *reg_value)
1229 {
1230         u8 sync_state = 0;
1231         u8 ts_lock = 0;
1232         u8 unlock_detected = 0;
1233         u8 data[2];
1234         int ret;
1235
1236         if (!tnr_dmd || !reg_value)
1237                 return -EINVAL;
1238
1239         ret = slvt_freeze_reg(tnr_dmd);
1240         if (ret)
1241                 return ret;
1242
1243         ret =
1244             cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
1245                                                &ts_lock,
1246                                                &unlock_detected);
1247         if (ret) {
1248                 slvt_unfreeze_reg(tnr_dmd);
1249                 return ret;
1250         }
1251
1252         if (sync_state != 6) {
1253                 slvt_unfreeze_reg(tnr_dmd);
1254                 return -EAGAIN;
1255         }
1256
1257         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1258                                      CXD2880_IO_TGT_DMD,
1259                                      0x00, 0x0b);
1260         if (ret) {
1261                 slvt_unfreeze_reg(tnr_dmd);
1262                 return ret;
1263         }
1264
1265         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1266                                      CXD2880_IO_TGT_DMD,
1267                                      0x13, data, sizeof(data));
1268         if (ret) {
1269                 slvt_unfreeze_reg(tnr_dmd);
1270                 return ret;
1271         }
1272
1273         slvt_unfreeze_reg(tnr_dmd);
1274
1275         *reg_value = (data[0] << 8) | data[1];
1276
1277         return ret;
1278 }
1279
1280 static int dvbt2_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
1281                           u32 reg_value, int *snr)
1282 {
1283         if (!tnr_dmd || !snr)
1284                 return -EINVAL;
1285
1286         if (reg_value == 0)
1287                 return -EAGAIN;
1288
1289         if (reg_value > 10876)
1290                 reg_value = 10876;
1291
1292         *snr = intlog10(reg_value) - intlog10(12600 - reg_value);
1293         *snr = (*snr + 839) / 1678 + 32000;
1294
1295         return 0;
1296 }
1297
1298 int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
1299                                  int *snr)
1300 {
1301         u16 reg_value = 0;
1302         int ret;
1303
1304         if (!tnr_dmd || !snr)
1305                 return -EINVAL;
1306
1307         *snr = -1000 * 1000;
1308
1309         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1310                 return -EINVAL;
1311
1312         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1313                 return -EINVAL;
1314
1315         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1316                 return -EINVAL;
1317
1318         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
1319                 ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
1320                 if (ret)
1321                         return ret;
1322
1323                 ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr);
1324         } else {
1325                 int snr_main = 0;
1326                 int snr_sub = 0;
1327
1328                 ret =
1329                     cxd2880_tnrdmd_dvbt2_mon_snr_diver(tnr_dmd, snr, &snr_main,
1330                                                        &snr_sub);
1331         }
1332
1333         return ret;
1334 }
1335
1336 int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd
1337                                        *tnr_dmd, int *snr,
1338                                        int *snr_main, int *snr_sub)
1339 {
1340         u16 reg_value = 0;
1341         u32 reg_value_sum = 0;
1342         int ret;
1343
1344         if (!tnr_dmd || !snr || !snr_main || !snr_sub)
1345                 return -EINVAL;
1346
1347         *snr = -1000 * 1000;
1348         *snr_main = -1000 * 1000;
1349         *snr_sub = -1000 * 1000;
1350
1351         if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
1352                 return -EINVAL;
1353
1354         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1355                 return -EINVAL;
1356
1357         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1358                 return -EINVAL;
1359
1360         ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
1361         if (!ret) {
1362                 ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr_main);
1363                 if (ret)
1364                         reg_value = 0;
1365         } else if (ret == -EAGAIN) {
1366                 reg_value = 0;
1367         } else {
1368                 return ret;
1369         }
1370
1371         reg_value_sum += reg_value;
1372
1373         ret = dvbt2_read_snr_reg(tnr_dmd->diver_sub, &reg_value);
1374         if (!ret) {
1375                 ret = dvbt2_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
1376                 if (ret)
1377                         reg_value = 0;
1378         } else if (ret == -EAGAIN) {
1379                 reg_value = 0;
1380         } else {
1381                 return ret;
1382         }
1383
1384         reg_value_sum += reg_value;
1385
1386         return dvbt2_calc_snr(tnr_dmd, reg_value_sum, snr);
1387 }
1388
1389 int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct
1390                                                  cxd2880_tnrdmd
1391                                                  *tnr_dmd,
1392                                                  u32 *pen)
1393 {
1394         int ret;
1395         u8 data[3];
1396
1397         if (!tnr_dmd || !pen)
1398                 return -EINVAL;
1399
1400         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1401                 return -EINVAL;
1402
1403         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1404                 return -EINVAL;
1405
1406         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1407                 return -EINVAL;
1408
1409         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1410                                      CXD2880_IO_TGT_DMD,
1411                                      0x00, 0x0b);
1412         if (ret)
1413                 return ret;
1414
1415         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1416                                      CXD2880_IO_TGT_DMD,
1417                                      0x39, data, sizeof(data));
1418         if (ret)
1419                 return ret;
1420
1421         if (!(data[0] & 0x01))
1422                 return -EAGAIN;
1423
1424         *pen = ((data[1] << 8) | data[2]);
1425
1426         return ret;
1427 }
1428
1429 int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd
1430                                              *tnr_dmd, int *ppm)
1431 {
1432         u8 ctl_val_reg[5];
1433         u8 nominal_rate_reg[5];
1434         u32 trl_ctl_val = 0;
1435         u32 trcg_nominal_rate = 0;
1436         int num;
1437         int den;
1438         int ret;
1439         u8 sync_state = 0;
1440         u8 ts_lock = 0;
1441         u8 unlock_detected = 0;
1442         s8 diff_upper = 0;
1443
1444         if (!tnr_dmd || !ppm)
1445                 return -EINVAL;
1446
1447         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1448                 return -EINVAL;
1449
1450         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1451                 return -EINVAL;
1452
1453         ret = slvt_freeze_reg(tnr_dmd);
1454         if (ret)
1455                 return ret;
1456
1457         ret =
1458             cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
1459                                                &ts_lock,
1460                                                &unlock_detected);
1461         if (ret) {
1462                 slvt_unfreeze_reg(tnr_dmd);
1463                 return ret;
1464         }
1465
1466         if (sync_state != 6) {
1467                 slvt_unfreeze_reg(tnr_dmd);
1468                 return -EAGAIN;
1469         }
1470
1471         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1472                                      CXD2880_IO_TGT_DMD,
1473                                      0x00, 0x0b);
1474         if (ret) {
1475                 slvt_unfreeze_reg(tnr_dmd);
1476                 return ret;
1477         }
1478
1479         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1480                                      CXD2880_IO_TGT_DMD,
1481                                      0x34, ctl_val_reg,
1482                                      sizeof(ctl_val_reg));
1483         if (ret) {
1484                 slvt_unfreeze_reg(tnr_dmd);
1485                 return ret;
1486         }
1487
1488         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1489                                      CXD2880_IO_TGT_DMD,
1490                                      0x00, 0x04);
1491         if (ret) {
1492                 slvt_unfreeze_reg(tnr_dmd);
1493                 return ret;
1494         }
1495
1496         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1497                                      CXD2880_IO_TGT_DMD,
1498                                      0x10, nominal_rate_reg,
1499                                      sizeof(nominal_rate_reg));
1500         if (ret) {
1501                 slvt_unfreeze_reg(tnr_dmd);
1502                 return ret;
1503         }
1504
1505         slvt_unfreeze_reg(tnr_dmd);
1506
1507         diff_upper =
1508             (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f);
1509
1510         if (diff_upper < -1 || diff_upper > 1)
1511                 return -EAGAIN;
1512
1513         trl_ctl_val = ctl_val_reg[1] << 24;
1514         trl_ctl_val |= ctl_val_reg[2] << 16;
1515         trl_ctl_val |= ctl_val_reg[3] << 8;
1516         trl_ctl_val |= ctl_val_reg[4];
1517
1518         trcg_nominal_rate = nominal_rate_reg[1] << 24;
1519         trcg_nominal_rate |= nominal_rate_reg[2] << 16;
1520         trcg_nominal_rate |= nominal_rate_reg[3] << 8;
1521         trcg_nominal_rate |= nominal_rate_reg[4];
1522
1523         trl_ctl_val >>= 1;
1524         trcg_nominal_rate >>= 1;
1525
1526         if (diff_upper == 1)
1527                 num =
1528                     (int)((trl_ctl_val + 0x80000000u) -
1529                           trcg_nominal_rate);
1530         else if (diff_upper == -1)
1531                 num =
1532                     -(int)((trcg_nominal_rate + 0x80000000u) -
1533                            trl_ctl_val);
1534         else
1535                 num = (int)(trl_ctl_val - trcg_nominal_rate);
1536
1537         den = (nominal_rate_reg[0] & 0x7f) << 24;
1538         den |= nominal_rate_reg[1] << 16;
1539         den |= nominal_rate_reg[2] << 8;
1540         den |= nominal_rate_reg[3];
1541         den = (den + (390625 / 2)) / 390625;
1542
1543         den >>= 1;
1544
1545         if (num >= 0)
1546                 *ppm = (num + (den / 2)) / den;
1547         else
1548                 *ppm = (num - (den / 2)) / den;
1549
1550         return 0;
1551 }
1552
1553 int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct
1554                                                  cxd2880_tnrdmd
1555                                                  *tnr_dmd,
1556                                                  int *ppm)
1557 {
1558         if (!tnr_dmd || !ppm)
1559                 return -EINVAL;
1560
1561         if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
1562                 return -EINVAL;
1563
1564         return cxd2880_tnrdmd_dvbt2_mon_sampling_offset(tnr_dmd->diver_sub,
1565                                                         ppm);
1566 }
1567
1568 int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
1569                                  enum cxd2880_dvbt2_plp_btype type,
1570                                  enum cxd2880_dvbt2_plp_constell *qam)
1571 {
1572         u8 data;
1573         u8 l1_post_ok = 0;
1574         int ret;
1575
1576         if (!tnr_dmd || !qam)
1577                 return -EINVAL;
1578
1579         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1580                 return -EINVAL;
1581
1582         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1583                 return -EINVAL;
1584
1585         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1586                 return -EINVAL;
1587
1588         ret = slvt_freeze_reg(tnr_dmd);
1589         if (ret)
1590                 return ret;
1591
1592         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1593                                      CXD2880_IO_TGT_DMD,
1594                                      0x00, 0x0b);
1595         if (ret) {
1596                 slvt_unfreeze_reg(tnr_dmd);
1597                 return ret;
1598         }
1599
1600         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1601                                      CXD2880_IO_TGT_DMD,
1602                                      0x86, &l1_post_ok, 1);
1603         if (ret) {
1604                 slvt_unfreeze_reg(tnr_dmd);
1605                 return ret;
1606         }
1607
1608         if (!(l1_post_ok & 0x01)) {
1609                 slvt_unfreeze_reg(tnr_dmd);
1610                 return -EAGAIN;
1611         }
1612
1613         if (type == CXD2880_DVBT2_PLP_COMMON) {
1614                 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1615                                              CXD2880_IO_TGT_DMD,
1616                                              0xb6, &data, 1);
1617                 if (ret) {
1618                         slvt_unfreeze_reg(tnr_dmd);
1619                         return ret;
1620                 }
1621
1622                 if (data == 0) {
1623                         slvt_unfreeze_reg(tnr_dmd);
1624                         return -EAGAIN;
1625                 }
1626
1627                 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1628                                              CXD2880_IO_TGT_DMD,
1629                                              0xb1, &data, 1);
1630                 if (ret) {
1631                         slvt_unfreeze_reg(tnr_dmd);
1632                         return ret;
1633                 }
1634         } else {
1635                 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1636                                              CXD2880_IO_TGT_DMD,
1637                                              0x9e, &data, 1);
1638                 if (ret) {
1639                         slvt_unfreeze_reg(tnr_dmd);
1640                         return ret;
1641                 }
1642         }
1643
1644         slvt_unfreeze_reg(tnr_dmd);
1645
1646         *qam = (enum cxd2880_dvbt2_plp_constell)(data & 0x07);
1647
1648         return ret;
1649 }
1650
1651 int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd
1652                                        *tnr_dmd,
1653                                        enum cxd2880_dvbt2_plp_btype
1654                                        type,
1655                                        enum
1656                                        cxd2880_dvbt2_plp_code_rate
1657                                        *code_rate)
1658 {
1659         u8 data;
1660         u8 l1_post_ok = 0;
1661         int ret;
1662
1663         if (!tnr_dmd || !code_rate)
1664                 return -EINVAL;
1665
1666         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1667                 return -EINVAL;
1668
1669         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1670                 return -EINVAL;
1671
1672         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1673                 return -EINVAL;
1674
1675         ret = slvt_freeze_reg(tnr_dmd);
1676         if (ret)
1677                 return ret;
1678
1679         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1680                                      CXD2880_IO_TGT_DMD,
1681                                      0x00, 0x0b);
1682         if (ret) {
1683                 slvt_unfreeze_reg(tnr_dmd);
1684                 return ret;
1685         }
1686
1687         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1688                                      CXD2880_IO_TGT_DMD,
1689                                      0x86, &l1_post_ok, 1);
1690         if (ret) {
1691                 slvt_unfreeze_reg(tnr_dmd);
1692                 return ret;
1693         }
1694
1695         if (!(l1_post_ok & 0x01)) {
1696                 slvt_unfreeze_reg(tnr_dmd);
1697                 return -EAGAIN;
1698         }
1699
1700         if (type == CXD2880_DVBT2_PLP_COMMON) {
1701                 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1702                                              CXD2880_IO_TGT_DMD,
1703                                              0xb6, &data, 1);
1704                 if (ret) {
1705                         slvt_unfreeze_reg(tnr_dmd);
1706                         return ret;
1707                 }
1708
1709                 if (data == 0) {
1710                         slvt_unfreeze_reg(tnr_dmd);
1711                         return -EAGAIN;
1712                 }
1713
1714                 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1715                                              CXD2880_IO_TGT_DMD,
1716                                              0xb0, &data, 1);
1717                 if (ret) {
1718                         slvt_unfreeze_reg(tnr_dmd);
1719                         return ret;
1720                 }
1721         } else {
1722                 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1723                                              CXD2880_IO_TGT_DMD,
1724                                              0x9d, &data, 1);
1725                 if (ret) {
1726                         slvt_unfreeze_reg(tnr_dmd);
1727                         return ret;
1728                 }
1729         }
1730
1731         slvt_unfreeze_reg(tnr_dmd);
1732
1733         *code_rate = (enum cxd2880_dvbt2_plp_code_rate)(data & 0x07);
1734
1735         return ret;
1736 }
1737
1738 int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd
1739                                      *tnr_dmd,
1740                                      enum cxd2880_dvbt2_profile
1741                                      *profile)
1742 {
1743         u8 data;
1744         int ret;
1745
1746         if (!tnr_dmd || !profile)
1747                 return -EINVAL;
1748
1749         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1750                 return -EINVAL;
1751
1752         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1753                 return -EINVAL;
1754
1755         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1756                                      CXD2880_IO_TGT_DMD,
1757                                      0x00, 0x0b);
1758         if (ret)
1759                 return ret;
1760
1761         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1762                                      CXD2880_IO_TGT_DMD,
1763                                      0x22, &data, sizeof(data));
1764         if (ret)
1765                 return ret;
1766
1767         if (data & 0x02) {
1768                 if (data & 0x01)
1769                         *profile = CXD2880_DVBT2_PROFILE_LITE;
1770                 else
1771                         *profile = CXD2880_DVBT2_PROFILE_BASE;
1772         } else {
1773                 ret = -EAGAIN;
1774                 if (tnr_dmd->diver_mode ==
1775                     CXD2880_TNRDMD_DIVERMODE_MAIN)
1776                         ret =
1777                             cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd->diver_sub,
1778                                                              profile);
1779
1780                 return ret;
1781         }
1782
1783         return 0;
1784 }
1785
1786 static int dvbt2_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
1787                           int rf_lvl, u8 *ssi)
1788 {
1789         enum cxd2880_dvbt2_plp_constell qam;
1790         enum cxd2880_dvbt2_plp_code_rate code_rate;
1791         int prel;
1792         int temp_ssi = 0;
1793         int ret;
1794
1795         if (!tnr_dmd || !ssi)
1796                 return -EINVAL;
1797
1798         ret =
1799             cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam);
1800         if (ret)
1801                 return ret;
1802
1803         ret =
1804             cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA,
1805                                                &code_rate);
1806         if (ret)
1807                 return ret;
1808
1809         if (code_rate > CXD2880_DVBT2_R2_5 || qam > CXD2880_DVBT2_QAM256)
1810                 return -EINVAL;
1811
1812         prel = rf_lvl - ref_dbm_1000[qam][code_rate];
1813
1814         if (prel < -15000)
1815                 temp_ssi = 0;
1816         else if (prel < 0)
1817                 temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
1818         else if (prel < 20000)
1819                 temp_ssi = (((4 * prel) + 500) / 1000) + 10;
1820         else if (prel < 35000)
1821                 temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
1822         else
1823                 temp_ssi = 100;
1824
1825         *ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
1826
1827         return ret;
1828 }
1829
1830 int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
1831                                  u8 *ssi)
1832 {
1833         int rf_lvl = 0;
1834         int ret;
1835
1836         if (!tnr_dmd || !ssi)
1837                 return -EINVAL;
1838
1839         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1840                 return -EINVAL;
1841
1842         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1843                 return -EINVAL;
1844
1845         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1846                 return -EINVAL;
1847
1848         ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
1849         if (ret)
1850                 return ret;
1851
1852         return dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);
1853 }
1854
1855 int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd
1856                                      *tnr_dmd, u8 *ssi)
1857 {
1858         int rf_lvl = 0;
1859         int ret;
1860
1861         if (!tnr_dmd || !ssi)
1862                 return -EINVAL;
1863
1864         if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
1865                 return -EINVAL;
1866
1867         if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1868                 return -EINVAL;
1869
1870         if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1871                 return -EINVAL;
1872
1873         ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
1874         if (ret)
1875                 return ret;
1876
1877         return dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);
1878 }