1879 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * cxd2880_tnrdmd_dvbt2_mon.c4 * Sony CXD2880 DVB-T2/T tuner + demodulator driver5 * DVB-T2 monitor functions6 *7 * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation8 */9 10#include "cxd2880_tnrdmd_mon.h"11#include "cxd2880_tnrdmd_dvbt2.h"12#include "cxd2880_tnrdmd_dvbt2_mon.h"13 14#include <linux/int_log.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_tnrdmd24 *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_tnrdmd63 *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_tnrdmd82 *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(struct159 cxd2880_tnrdmd160 *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_l1pre175 *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_sub215 (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_tnrdmd351 *tnr_dmd,352 enum cxd2880_dvbt2_version353 *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_sub392 (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_tnrdmd509 *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_tnrdmd604 *tnr_dmd,605 enum606 cxd2880_dvbt2_plp_btype607 type,608 struct cxd2880_dvbt2_plp609 *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 else657 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_tnrdmd710 *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_tnrdmd769 *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_sub807 (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_tnrdmd863 *tnr_dmd,864 struct cxd2880_dvbt2_l1post865 *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_tnrdmd917 *tnr_dmd,918 enum cxd2880_dvbt2_plp_btype919 type,920 struct cxd2880_dvbt2_bbheader921 *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 else1002 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_tnrdmd1045 *tnr_dmd,1046 enum1047 cxd2880_dvbt2_plp_btype1048 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 else1114 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 else1140 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_tnrdmd1157 *tnr_dmd,1158 enum1159 cxd2880_tnrdmd_spectrum_sense1160 *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, ®_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_tnrdmd1337 *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, ®_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, ®_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(struct1390 cxd2880_tnrdmd1391 *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_tnrdmd1430 *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 else1535 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 else1548 *ppm = (num - (den / 2)) / den;1549 1550 return 0;1551}1552 1553int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct1554 cxd2880_tnrdmd1555 *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_tnrdmd1652 *tnr_dmd,1653 enum cxd2880_dvbt2_plp_btype1654 type,1655 enum1656 cxd2880_dvbt2_plp_code_rate1657 *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_tnrdmd1739 *tnr_dmd,1740 enum cxd2880_dvbt2_profile1741 *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 else1771 *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 else1823 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_tnrdmd1856 *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