Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * cxd2880_tnrdmd_dvbt2_mon.c
0004  * Sony CXD2880 DVB-T2/T tuner + demodulator driver
0005  * DVB-T2 monitor functions
0006  *
0007  * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
0008  */
0009 
0010 #include "cxd2880_tnrdmd_mon.h"
0011 #include "cxd2880_tnrdmd_dvbt2.h"
0012 #include "cxd2880_tnrdmd_dvbt2_mon.h"
0013 
0014 #include <media/dvb_math.h>
0015 
0016 static const int ref_dbm_1000[4][8] = {
0017     {-96000, -95000, -94000, -93000, -92000, -92000, -98000, -97000},
0018     {-91000, -89000, -88000, -87000, -86000, -86000, -93000, -92000},
0019     {-86000, -85000, -83000, -82000, -81000, -80000, -89000, -88000},
0020     {-82000, -80000, -78000, -76000, -75000, -74000, -86000, -84000},
0021 };
0022 
0023 int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
0024                        *tnr_dmd, u8 *sync_stat,
0025                        u8 *ts_lock_stat,
0026                        u8 *unlock_detected)
0027 {
0028     u8 data;
0029     int ret;
0030 
0031     if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected)
0032         return -EINVAL;
0033 
0034     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0035         return -EINVAL;
0036 
0037     if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
0038         return -EINVAL;
0039 
0040     ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0041                      CXD2880_IO_TGT_DMD,
0042                      0x00, 0x0b);
0043     if (ret)
0044         return ret;
0045 
0046     ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0047                      CXD2880_IO_TGT_DMD,
0048                      0x10, &data, sizeof(data));
0049     if (ret)
0050         return ret;
0051 
0052     *sync_stat = data & 0x07;
0053     *ts_lock_stat = ((data & 0x20) ? 1 : 0);
0054     *unlock_detected = ((data & 0x10) ? 1 : 0);
0055 
0056     if (*sync_stat == 0x07)
0057         return -EAGAIN;
0058 
0059     return 0;
0060 }
0061 
0062 int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
0063                        *tnr_dmd,
0064                        u8 *sync_stat,
0065                        u8 *unlock_detected)
0066 {
0067     u8 ts_lock_stat = 0;
0068 
0069     if (!tnr_dmd || !sync_stat || !unlock_detected)
0070         return -EINVAL;
0071 
0072     if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
0073         return -EINVAL;
0074 
0075     return cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub,
0076                           sync_stat,
0077                           &ts_lock_stat,
0078                           unlock_detected);
0079 }
0080 
0081 int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
0082                         *tnr_dmd, int *offset)
0083 {
0084     u8 data[4];
0085     u32 ctl_val = 0;
0086     u8 sync_state = 0;
0087     u8 ts_lock = 0;
0088     u8 unlock_detected = 0;
0089     int ret;
0090 
0091     if (!tnr_dmd || !offset)
0092         return -EINVAL;
0093 
0094     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0095         return -EINVAL;
0096 
0097     if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
0098         return -EINVAL;
0099 
0100     ret = slvt_freeze_reg(tnr_dmd);
0101     if (ret)
0102         return ret;
0103 
0104     ret =
0105         cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
0106                            &ts_lock,
0107                            &unlock_detected);
0108     if (ret) {
0109         slvt_unfreeze_reg(tnr_dmd);
0110         return ret;
0111     }
0112 
0113     if (sync_state != 6) {
0114         slvt_unfreeze_reg(tnr_dmd);
0115         return -EAGAIN;
0116     }
0117 
0118     ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0119                      CXD2880_IO_TGT_DMD,
0120                      0x00, 0x0b);
0121     if (ret) {
0122         slvt_unfreeze_reg(tnr_dmd);
0123         return ret;
0124     }
0125 
0126     ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0127                      CXD2880_IO_TGT_DMD,
0128                      0x30, data, sizeof(data));
0129     if (ret) {
0130         slvt_unfreeze_reg(tnr_dmd);
0131         return ret;
0132     }
0133 
0134     slvt_unfreeze_reg(tnr_dmd);
0135 
0136     ctl_val =
0137         ((data[0] & 0x0f) << 24) | (data[1] << 16) | (data[2] << 8)
0138         | (data[3]);
0139     *offset = cxd2880_convert2s_complement(ctl_val, 28);
0140 
0141     switch (tnr_dmd->bandwidth) {
0142     case CXD2880_DTV_BW_1_7_MHZ:
0143         *offset = -1 * ((*offset) / 582);
0144         break;
0145     case CXD2880_DTV_BW_5_MHZ:
0146     case CXD2880_DTV_BW_6_MHZ:
0147     case CXD2880_DTV_BW_7_MHZ:
0148     case CXD2880_DTV_BW_8_MHZ:
0149         *offset = -1 * ((*offset) * tnr_dmd->bandwidth / 940);
0150         break;
0151     default:
0152         return -EINVAL;
0153     }
0154 
0155     return 0;
0156 }
0157 
0158 int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
0159                         cxd2880_tnrdmd
0160                         *tnr_dmd,
0161                         int *offset)
0162 {
0163     if (!tnr_dmd || !offset)
0164         return -EINVAL;
0165 
0166     if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
0167         return -EINVAL;
0168 
0169     return cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub,
0170                                offset);
0171 }
0172 
0173 int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
0174                     struct cxd2880_dvbt2_l1pre
0175                     *l1_pre)
0176 {
0177     u8 data[37];
0178     u8 sync_state = 0;
0179     u8 ts_lock = 0;
0180     u8 unlock_detected = 0;
0181     u8 version = 0;
0182     enum cxd2880_dvbt2_profile profile;
0183     int ret;
0184 
0185     if (!tnr_dmd || !l1_pre)
0186         return -EINVAL;
0187 
0188     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0189         return -EINVAL;
0190 
0191     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0192         return -EINVAL;
0193 
0194     if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
0195         return -EINVAL;
0196 
0197     ret = slvt_freeze_reg(tnr_dmd);
0198     if (ret)
0199         return ret;
0200 
0201     ret =
0202         cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
0203                            &ts_lock,
0204                            &unlock_detected);
0205     if (ret) {
0206         slvt_unfreeze_reg(tnr_dmd);
0207         return ret;
0208     }
0209 
0210     if (sync_state < 5) {
0211         if (tnr_dmd->diver_mode ==
0212             CXD2880_TNRDMD_DIVERMODE_MAIN) {
0213             ret =
0214                 cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
0215                 (tnr_dmd, &sync_state, &unlock_detected);
0216             if (ret) {
0217                 slvt_unfreeze_reg(tnr_dmd);
0218                 return ret;
0219             }
0220 
0221             if (sync_state < 5) {
0222                 slvt_unfreeze_reg(tnr_dmd);
0223                 return -EAGAIN;
0224             }
0225         } else {
0226             slvt_unfreeze_reg(tnr_dmd);
0227             return -EAGAIN;
0228         }
0229     }
0230 
0231     ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile);
0232     if (ret) {
0233         slvt_unfreeze_reg(tnr_dmd);
0234         return ret;
0235     }
0236 
0237     ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0238                      CXD2880_IO_TGT_DMD,
0239                      0x00, 0x0b);
0240     if (ret) {
0241         slvt_unfreeze_reg(tnr_dmd);
0242         return ret;
0243     }
0244 
0245     ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0246                      CXD2880_IO_TGT_DMD,
0247                      0x61, data, sizeof(data));
0248     if (ret) {
0249         slvt_unfreeze_reg(tnr_dmd);
0250         return ret;
0251     }
0252     slvt_unfreeze_reg(tnr_dmd);
0253 
0254     l1_pre->type = (enum cxd2880_dvbt2_l1pre_type)data[0];
0255     l1_pre->bw_ext = data[1] & 0x01;
0256     l1_pre->s1 = (enum cxd2880_dvbt2_s1)(data[2] & 0x07);
0257     l1_pre->s2 = data[3] & 0x0f;
0258     l1_pre->l1_rep = data[4] & 0x01;
0259     l1_pre->gi = (enum cxd2880_dvbt2_guard)(data[5] & 0x07);
0260     l1_pre->papr = (enum cxd2880_dvbt2_papr)(data[6] & 0x0f);
0261     l1_pre->mod =
0262         (enum cxd2880_dvbt2_l1post_constell)(data[7] & 0x0f);
0263     l1_pre->cr = (enum cxd2880_dvbt2_l1post_cr)(data[8] & 0x03);
0264     l1_pre->fec =
0265         (enum cxd2880_dvbt2_l1post_fec_type)(data[9] & 0x03);
0266     l1_pre->l1_post_size = (data[10] & 0x03) << 16;
0267     l1_pre->l1_post_size |= (data[11]) << 8;
0268     l1_pre->l1_post_size |= (data[12]);
0269     l1_pre->l1_post_info_size = (data[13] & 0x03) << 16;
0270     l1_pre->l1_post_info_size |= (data[14]) << 8;
0271     l1_pre->l1_post_info_size |= (data[15]);
0272     l1_pre->pp = (enum cxd2880_dvbt2_pp)(data[16] & 0x0f);
0273     l1_pre->tx_id_availability = data[17];
0274     l1_pre->cell_id = (data[18] << 8);
0275     l1_pre->cell_id |= (data[19]);
0276     l1_pre->network_id = (data[20] << 8);
0277     l1_pre->network_id |= (data[21]);
0278     l1_pre->sys_id = (data[22] << 8);
0279     l1_pre->sys_id |= (data[23]);
0280     l1_pre->num_frames = data[24];
0281     l1_pre->num_symbols = (data[25] & 0x0f) << 8;
0282     l1_pre->num_symbols |= data[26];
0283     l1_pre->regen = data[27] & 0x07;
0284     l1_pre->post_ext = data[28] & 0x01;
0285     l1_pre->num_rf_freqs = data[29] & 0x07;
0286     l1_pre->rf_idx = data[30] & 0x07;
0287     version = (data[31] & 0x03) << 2;
0288     version |= (data[32] & 0xc0) >> 6;
0289     l1_pre->t2_version = (enum cxd2880_dvbt2_version)version;
0290     l1_pre->l1_post_scrambled = (data[32] & 0x20) >> 5;
0291     l1_pre->t2_base_lite = (data[32] & 0x10) >> 4;
0292     l1_pre->crc32 = (data[33] << 24);
0293     l1_pre->crc32 |= (data[34] << 16);
0294     l1_pre->crc32 |= (data[35] << 8);
0295     l1_pre->crc32 |= data[36];
0296 
0297     if (profile == CXD2880_DVBT2_PROFILE_BASE) {
0298         switch ((l1_pre->s2 >> 1)) {
0299         case CXD2880_DVBT2_BASE_S2_M1K_G_ANY:
0300             l1_pre->fft_mode = CXD2880_DVBT2_M1K;
0301             break;
0302         case CXD2880_DVBT2_BASE_S2_M2K_G_ANY:
0303             l1_pre->fft_mode = CXD2880_DVBT2_M2K;
0304             break;
0305         case CXD2880_DVBT2_BASE_S2_M4K_G_ANY:
0306             l1_pre->fft_mode = CXD2880_DVBT2_M4K;
0307             break;
0308         case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT:
0309         case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2:
0310             l1_pre->fft_mode = CXD2880_DVBT2_M8K;
0311             break;
0312         case CXD2880_DVBT2_BASE_S2_M16K_G_ANY:
0313             l1_pre->fft_mode = CXD2880_DVBT2_M16K;
0314             break;
0315         case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT:
0316         case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2:
0317             l1_pre->fft_mode = CXD2880_DVBT2_M32K;
0318             break;
0319         default:
0320             return -EAGAIN;
0321         }
0322     } else if (profile == CXD2880_DVBT2_PROFILE_LITE) {
0323         switch ((l1_pre->s2 >> 1)) {
0324         case CXD2880_DVBT2_LITE_S2_M2K_G_ANY:
0325             l1_pre->fft_mode = CXD2880_DVBT2_M2K;
0326             break;
0327         case CXD2880_DVBT2_LITE_S2_M4K_G_ANY:
0328             l1_pre->fft_mode = CXD2880_DVBT2_M4K;
0329             break;
0330         case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT:
0331         case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2:
0332             l1_pre->fft_mode = CXD2880_DVBT2_M8K;
0333             break;
0334         case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT:
0335         case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2:
0336             l1_pre->fft_mode = CXD2880_DVBT2_M16K;
0337             break;
0338         default:
0339             return -EAGAIN;
0340         }
0341     } else {
0342         return -EAGAIN;
0343     }
0344 
0345     l1_pre->mixed = l1_pre->s2 & 0x01;
0346 
0347     return ret;
0348 }
0349 
0350 int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
0351                      *tnr_dmd,
0352                      enum cxd2880_dvbt2_version
0353                      *ver)
0354 {
0355     u8 data[2];
0356     u8 sync_state = 0;
0357     u8 ts_lock = 0;
0358     u8 unlock_detected = 0;
0359     u8 version = 0;
0360     int ret;
0361 
0362     if (!tnr_dmd || !ver)
0363         return -EINVAL;
0364 
0365     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0366         return -EINVAL;
0367 
0368     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0369         return -EINVAL;
0370 
0371     if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
0372         return -EINVAL;
0373 
0374     ret = slvt_freeze_reg(tnr_dmd);
0375     if (ret)
0376         return ret;
0377 
0378     ret =
0379         cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
0380                            &ts_lock,
0381                            &unlock_detected);
0382     if (ret) {
0383         slvt_unfreeze_reg(tnr_dmd);
0384         return ret;
0385     }
0386 
0387     if (sync_state < 5) {
0388         if (tnr_dmd->diver_mode ==
0389             CXD2880_TNRDMD_DIVERMODE_MAIN) {
0390             ret =
0391                 cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
0392                 (tnr_dmd, &sync_state, &unlock_detected);
0393             if (ret) {
0394                 slvt_unfreeze_reg(tnr_dmd);
0395                 return ret;
0396             }
0397 
0398             if (sync_state < 5) {
0399                 slvt_unfreeze_reg(tnr_dmd);
0400                 return -EAGAIN;
0401             }
0402         } else {
0403             slvt_unfreeze_reg(tnr_dmd);
0404             return -EAGAIN;
0405         }
0406     }
0407 
0408     ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0409                      CXD2880_IO_TGT_DMD,
0410                      0x00, 0x0b);
0411     if (ret) {
0412         slvt_unfreeze_reg(tnr_dmd);
0413         return ret;
0414     }
0415 
0416     ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0417                      CXD2880_IO_TGT_DMD,
0418                      0x80, data, sizeof(data));
0419     if (ret) {
0420         slvt_unfreeze_reg(tnr_dmd);
0421         return ret;
0422     }
0423 
0424     slvt_unfreeze_reg(tnr_dmd);
0425 
0426     version = ((data[0] & 0x03) << 2);
0427     version |= ((data[1] & 0xc0) >> 6);
0428     *ver = (enum cxd2880_dvbt2_version)version;
0429 
0430     return ret;
0431 }
0432 
0433 int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
0434                   struct cxd2880_dvbt2_ofdm *ofdm)
0435 {
0436     u8 data[5];
0437     u8 sync_state = 0;
0438     u8 ts_lock = 0;
0439     u8 unlock_detected = 0;
0440     int ret;
0441 
0442     if (!tnr_dmd || !ofdm)
0443         return -EINVAL;
0444 
0445     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0446         return -EINVAL;
0447 
0448     if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
0449         return -EINVAL;
0450 
0451     ret = slvt_freeze_reg(tnr_dmd);
0452     if (ret)
0453         return ret;
0454 
0455     ret =
0456         cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
0457                            &ts_lock,
0458                            &unlock_detected);
0459     if (ret) {
0460         slvt_unfreeze_reg(tnr_dmd);
0461         return ret;
0462     }
0463 
0464     if (sync_state != 6) {
0465         slvt_unfreeze_reg(tnr_dmd);
0466 
0467         ret = -EAGAIN;
0468 
0469         if (tnr_dmd->diver_mode ==
0470             CXD2880_TNRDMD_DIVERMODE_MAIN)
0471             ret =
0472                 cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd->diver_sub,
0473                               ofdm);
0474 
0475         return ret;
0476     }
0477 
0478     ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0479                      CXD2880_IO_TGT_DMD,
0480                      0x00, 0x0b);
0481     if (ret) {
0482         slvt_unfreeze_reg(tnr_dmd);
0483         return ret;
0484     }
0485 
0486     ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0487                      CXD2880_IO_TGT_DMD,
0488                      0x1d, data, sizeof(data));
0489     if (ret) {
0490         slvt_unfreeze_reg(tnr_dmd);
0491         return ret;
0492     }
0493 
0494     slvt_unfreeze_reg(tnr_dmd);
0495 
0496     ofdm->mixed = ((data[0] & 0x20) ? 1 : 0);
0497     ofdm->is_miso = ((data[0] & 0x10) >> 4);
0498     ofdm->mode = (enum cxd2880_dvbt2_mode)(data[0] & 0x07);
0499     ofdm->gi = (enum cxd2880_dvbt2_guard)((data[1] & 0x70) >> 4);
0500     ofdm->pp = (enum cxd2880_dvbt2_pp)(data[1] & 0x07);
0501     ofdm->bw_ext = (data[2] & 0x10) >> 4;
0502     ofdm->papr = (enum cxd2880_dvbt2_papr)(data[2] & 0x0f);
0503     ofdm->num_symbols = (data[3] << 8) | data[4];
0504 
0505     return 0;
0506 }
0507 
0508 int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
0509                        *tnr_dmd, u8 *plp_ids,
0510                        u8 *num_plps)
0511 {
0512     u8 l1_post_ok = 0;
0513     int ret;
0514 
0515     if (!tnr_dmd || !num_plps)
0516         return -EINVAL;
0517 
0518     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0519         return -EINVAL;
0520 
0521     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0522         return -EINVAL;
0523 
0524     if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
0525         return -EINVAL;
0526 
0527     ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0528                      CXD2880_IO_TGT_DMD,
0529                      0x00, 0x0b);
0530     if (ret)
0531         return ret;
0532 
0533     ret = slvt_freeze_reg(tnr_dmd);
0534     if (ret)
0535         return ret;
0536 
0537     ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0538                      CXD2880_IO_TGT_DMD,
0539                      0x86, &l1_post_ok, 1);
0540     if (ret) {
0541         slvt_unfreeze_reg(tnr_dmd);
0542         return ret;
0543     }
0544 
0545     if (!(l1_post_ok & 0x01)) {
0546         slvt_unfreeze_reg(tnr_dmd);
0547         return -EAGAIN;
0548     }
0549 
0550     ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0551                      CXD2880_IO_TGT_DMD,
0552                      0xc1, num_plps, 1);
0553     if (ret) {
0554         slvt_unfreeze_reg(tnr_dmd);
0555         return ret;
0556     }
0557 
0558     if (*num_plps == 0) {
0559         slvt_unfreeze_reg(tnr_dmd);
0560         return -EINVAL;
0561     }
0562 
0563     if (!plp_ids) {
0564         slvt_unfreeze_reg(tnr_dmd);
0565         return 0;
0566     }
0567 
0568     ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0569                      CXD2880_IO_TGT_DMD,
0570                      0xc2,
0571                      plp_ids,
0572                      ((*num_plps > 62) ?
0573                      62 : *num_plps));
0574     if (ret) {
0575         slvt_unfreeze_reg(tnr_dmd);
0576         return ret;
0577     }
0578 
0579     if (*num_plps > 62) {
0580         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0581                          CXD2880_IO_TGT_DMD,
0582                          0x00, 0x0c);
0583         if (ret) {
0584             slvt_unfreeze_reg(tnr_dmd);
0585             return ret;
0586         }
0587 
0588         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0589                          CXD2880_IO_TGT_DMD,
0590                          0x10, plp_ids + 62,
0591                          *num_plps - 62);
0592         if (ret) {
0593             slvt_unfreeze_reg(tnr_dmd);
0594             return ret;
0595         }
0596     }
0597 
0598     slvt_unfreeze_reg(tnr_dmd);
0599 
0600     return 0;
0601 }
0602 
0603 int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
0604                     *tnr_dmd,
0605                     enum
0606                     cxd2880_dvbt2_plp_btype
0607                     type,
0608                     struct cxd2880_dvbt2_plp
0609                     *plp_info)
0610 {
0611     u8 data[20];
0612     u8 addr = 0;
0613     u8 index = 0;
0614     u8 l1_post_ok = 0;
0615     int ret;
0616 
0617     if (!tnr_dmd || !plp_info)
0618         return -EINVAL;
0619 
0620     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0621         return -EINVAL;
0622 
0623     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0624         return -EINVAL;
0625 
0626     if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
0627         return -EINVAL;
0628 
0629     ret = slvt_freeze_reg(tnr_dmd);
0630     if (ret)
0631         return ret;
0632 
0633     ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0634                      CXD2880_IO_TGT_DMD,
0635                      0x00, 0x0b);
0636     if (ret) {
0637         slvt_unfreeze_reg(tnr_dmd);
0638         return ret;
0639     }
0640 
0641     ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0642                      CXD2880_IO_TGT_DMD,
0643                      0x86, &l1_post_ok, 1);
0644     if (ret) {
0645         slvt_unfreeze_reg(tnr_dmd);
0646         return ret;
0647     }
0648 
0649     if (!l1_post_ok) {
0650         slvt_unfreeze_reg(tnr_dmd);
0651         return -EAGAIN;
0652     }
0653 
0654     if (type == CXD2880_DVBT2_PLP_COMMON)
0655         addr = 0xa9;
0656     else
0657         addr = 0x96;
0658 
0659     ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0660                      CXD2880_IO_TGT_DMD,
0661                      addr, data, sizeof(data));
0662     if (ret) {
0663         slvt_unfreeze_reg(tnr_dmd);
0664         return ret;
0665     }
0666 
0667     slvt_unfreeze_reg(tnr_dmd);
0668 
0669     if (type == CXD2880_DVBT2_PLP_COMMON && !data[13])
0670         return -EAGAIN;
0671 
0672     plp_info->id = data[index++];
0673     plp_info->type =
0674         (enum cxd2880_dvbt2_plp_type)(data[index++] & 0x07);
0675     plp_info->payload =
0676         (enum cxd2880_dvbt2_plp_payload)(data[index++] & 0x1f);
0677     plp_info->ff = data[index++] & 0x01;
0678     plp_info->first_rf_idx = data[index++] & 0x07;
0679     plp_info->first_frm_idx = data[index++];
0680     plp_info->group_id = data[index++];
0681     plp_info->plp_cr =
0682         (enum cxd2880_dvbt2_plp_code_rate)(data[index++] & 0x07);
0683     plp_info->constell =
0684         (enum cxd2880_dvbt2_plp_constell)(data[index++] & 0x07);
0685     plp_info->rot = data[index++] & 0x01;
0686     plp_info->fec =
0687         (enum cxd2880_dvbt2_plp_fec)(data[index++] & 0x03);
0688     plp_info->num_blocks_max = (data[index++] & 0x03) << 8;
0689     plp_info->num_blocks_max |= data[index++];
0690     plp_info->frm_int = data[index++];
0691     plp_info->til_len = data[index++];
0692     plp_info->til_type = data[index++] & 0x01;
0693 
0694     plp_info->in_band_a_flag = data[index++] & 0x01;
0695     plp_info->rsvd = data[index++] << 8;
0696     plp_info->rsvd |= data[index++];
0697 
0698     plp_info->in_band_b_flag =
0699         (plp_info->rsvd & 0x8000) >> 15;
0700     plp_info->plp_mode =
0701         (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000c) >> 2);
0702     plp_info->static_flag = (plp_info->rsvd & 0x0002) >> 1;
0703     plp_info->static_padding_flag = plp_info->rsvd & 0x0001;
0704     plp_info->rsvd = (plp_info->rsvd & 0x7ff0) >> 4;
0705 
0706     return 0;
0707 }
0708 
0709 int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
0710                         *tnr_dmd,
0711                         u8 *plp_error)
0712 {
0713     u8 data;
0714     int ret;
0715 
0716     if (!tnr_dmd || !plp_error)
0717         return -EINVAL;
0718 
0719     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0720         return -EINVAL;
0721 
0722     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0723         return -EINVAL;
0724 
0725     if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
0726         return -EINVAL;
0727 
0728     ret = slvt_freeze_reg(tnr_dmd);
0729     if (ret)
0730         return ret;
0731 
0732     ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0733                      CXD2880_IO_TGT_DMD,
0734                      0x00, 0x0b);
0735     if (ret) {
0736         slvt_unfreeze_reg(tnr_dmd);
0737         return ret;
0738     }
0739 
0740     ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0741                      CXD2880_IO_TGT_DMD,
0742                      0x86, &data, 1);
0743     if (ret) {
0744         slvt_unfreeze_reg(tnr_dmd);
0745         return ret;
0746     }
0747 
0748     if ((data & 0x01) == 0x00) {
0749         slvt_unfreeze_reg(tnr_dmd);
0750         return -EAGAIN;
0751     }
0752 
0753     ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0754                      CXD2880_IO_TGT_DMD,
0755                      0xc0, &data, 1);
0756     if (ret) {
0757         slvt_unfreeze_reg(tnr_dmd);
0758         return ret;
0759     }
0760 
0761     slvt_unfreeze_reg(tnr_dmd);
0762 
0763     *plp_error = data & 0x01;
0764 
0765     return 0;
0766 }
0767 
0768 int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
0769                        *tnr_dmd, u8 *l1_change)
0770 {
0771     u8 data;
0772     u8 sync_state = 0;
0773     u8 ts_lock = 0;
0774     u8 unlock_detected = 0;
0775     int ret;
0776 
0777     if (!tnr_dmd || !l1_change)
0778         return -EINVAL;
0779 
0780     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0781         return -EINVAL;
0782 
0783     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0784         return -EINVAL;
0785 
0786     if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
0787         return -EINVAL;
0788 
0789     ret = slvt_freeze_reg(tnr_dmd);
0790     if (ret)
0791         return ret;
0792 
0793     ret =
0794         cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
0795                            &ts_lock,
0796                            &unlock_detected);
0797     if (ret) {
0798         slvt_unfreeze_reg(tnr_dmd);
0799         return ret;
0800     }
0801 
0802     if (sync_state < 5) {
0803         if (tnr_dmd->diver_mode ==
0804             CXD2880_TNRDMD_DIVERMODE_MAIN) {
0805             ret =
0806                 cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
0807                 (tnr_dmd, &sync_state, &unlock_detected);
0808             if (ret) {
0809                 slvt_unfreeze_reg(tnr_dmd);
0810                 return ret;
0811             }
0812 
0813             if (sync_state < 5) {
0814                 slvt_unfreeze_reg(tnr_dmd);
0815                 return -EAGAIN;
0816             }
0817         } else {
0818             slvt_unfreeze_reg(tnr_dmd);
0819             return -EAGAIN;
0820         }
0821     }
0822 
0823     ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0824                      CXD2880_IO_TGT_DMD,
0825                      0x00, 0x0b);
0826     if (ret) {
0827         slvt_unfreeze_reg(tnr_dmd);
0828         return ret;
0829     }
0830 
0831     ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0832                      CXD2880_IO_TGT_DMD,
0833                      0x5f, &data, sizeof(data));
0834     if (ret) {
0835         slvt_unfreeze_reg(tnr_dmd);
0836         return ret;
0837     }
0838 
0839     *l1_change = data & 0x01;
0840     if (*l1_change) {
0841         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0842                          CXD2880_IO_TGT_DMD,
0843                          0x00, 0x22);
0844         if (ret) {
0845             slvt_unfreeze_reg(tnr_dmd);
0846             return ret;
0847         }
0848 
0849         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0850                          CXD2880_IO_TGT_DMD,
0851                          0x16, 0x01);
0852         if (ret) {
0853             slvt_unfreeze_reg(tnr_dmd);
0854             return ret;
0855         }
0856     }
0857     slvt_unfreeze_reg(tnr_dmd);
0858 
0859     return 0;
0860 }
0861 
0862 int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
0863                      *tnr_dmd,
0864                      struct cxd2880_dvbt2_l1post
0865                      *l1_post)
0866 {
0867     u8 data[16];
0868     int ret;
0869 
0870     if (!tnr_dmd || !l1_post)
0871         return -EINVAL;
0872 
0873     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0874         return -EINVAL;
0875 
0876     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0877         return -EINVAL;
0878 
0879     if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
0880         return -EINVAL;
0881 
0882     ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0883                      CXD2880_IO_TGT_DMD,
0884                      0x00, 0x0b);
0885     if (ret)
0886         return ret;
0887 
0888     ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0889                      CXD2880_IO_TGT_DMD,
0890                      0x86, data, sizeof(data));
0891     if (ret)
0892         return ret;
0893 
0894     if (!(data[0] & 0x01))
0895         return -EAGAIN;
0896 
0897     l1_post->sub_slices_per_frame = (data[1] & 0x7f) << 8;
0898     l1_post->sub_slices_per_frame |= data[2];
0899     l1_post->num_plps = data[3];
0900     l1_post->num_aux = data[4] & 0x0f;
0901     l1_post->aux_cfg_rfu = data[5];
0902     l1_post->rf_idx = data[6] & 0x07;
0903     l1_post->freq = data[7] << 24;
0904     l1_post->freq |= data[8] << 16;
0905     l1_post->freq |= data[9] << 8;
0906     l1_post->freq |= data[10];
0907     l1_post->fef_type = data[11] & 0x0f;
0908     l1_post->fef_length = data[12] << 16;
0909     l1_post->fef_length |= data[13] << 8;
0910     l1_post->fef_length |= data[14];
0911     l1_post->fef_intvl = data[15];
0912 
0913     return 0;
0914 }
0915 
0916 int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
0917                       *tnr_dmd,
0918                       enum cxd2880_dvbt2_plp_btype
0919                       type,
0920                       struct cxd2880_dvbt2_bbheader
0921                       *bbheader)
0922 {
0923     u8 sync_state = 0;
0924     u8 ts_lock = 0;
0925     u8 unlock_detected = 0;
0926     u8 data[14];
0927     u8 addr = 0;
0928     int ret;
0929 
0930     if (!tnr_dmd || !bbheader)
0931         return -EINVAL;
0932 
0933     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0934         return -EINVAL;
0935 
0936     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0937         return -EINVAL;
0938 
0939     if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
0940         return -EINVAL;
0941 
0942     ret = slvt_freeze_reg(tnr_dmd);
0943     if (ret)
0944         return ret;
0945 
0946     ret =
0947         cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
0948                                &ts_lock,
0949                                &unlock_detected);
0950     if (ret) {
0951         slvt_unfreeze_reg(tnr_dmd);
0952         return ret;
0953     }
0954 
0955     if (!ts_lock) {
0956         slvt_unfreeze_reg(tnr_dmd);
0957         return -EAGAIN;
0958     }
0959 
0960     ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0961                      CXD2880_IO_TGT_DMD,
0962                      0x00, 0x0b);
0963     if (ret) {
0964         slvt_unfreeze_reg(tnr_dmd);
0965         return ret;
0966     }
0967 
0968     if (type == CXD2880_DVBT2_PLP_COMMON) {
0969         u8 l1_post_ok;
0970         u8 data;
0971 
0972         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0973                          CXD2880_IO_TGT_DMD,
0974                          0x86, &l1_post_ok, 1);
0975         if (ret) {
0976             slvt_unfreeze_reg(tnr_dmd);
0977             return ret;
0978         }
0979 
0980         if (!(l1_post_ok & 0x01)) {
0981             slvt_unfreeze_reg(tnr_dmd);
0982             return -EAGAIN;
0983         }
0984 
0985         ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0986                          CXD2880_IO_TGT_DMD,
0987                          0xb6, &data, 1);
0988         if (ret) {
0989             slvt_unfreeze_reg(tnr_dmd);
0990             return ret;
0991         }
0992 
0993         if (data == 0) {
0994             slvt_unfreeze_reg(tnr_dmd);
0995             return -EAGAIN;
0996         }
0997     }
0998 
0999     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 }