linux/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
<<
>>
Prefs
   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
  16static 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
  23int 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
  62int 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
  81int 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
 158int 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
 173int 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
 350int 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
 433int 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
 508int 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
 603int 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
 709int 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
 768int 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
 862int 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
 916int 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
1044int 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
1156int 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
1227static 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
1280static 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
1298int 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
1336int 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
1389int 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
1429int 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
1553int 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
1568int 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
1651int 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
1738int 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
1786static 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
1830int 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
1855int 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}
1879