cxd2880_tnrdmd_dvbt_mon.c (15953B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * cxd2880_tnrdmd_dvbt_mon.c 4 * Sony CXD2880 DVB-T2/T tuner + demodulator driver 5 * DVB-T 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_dvbt.h" 12#include "cxd2880_tnrdmd_dvbt_mon.h" 13 14#include <media/dvb_math.h> 15 16static const int ref_dbm_1000[3][5] = { 17 {-93000, -91000, -90000, -89000, -88000}, 18 {-87000, -85000, -84000, -83000, -82000}, 19 {-82000, -80000, -78000, -77000, -76000}, 20}; 21 22static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd); 23 24int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd 25 *tnr_dmd, u8 *sync_stat, 26 u8 *ts_lock_stat, 27 u8 *unlock_detected) 28{ 29 u8 rdata = 0x00; 30 int ret; 31 32 if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected) 33 return -EINVAL; 34 35 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 36 return -EINVAL; 37 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) 38 return -EINVAL; 39 40 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 41 CXD2880_IO_TGT_DMD, 42 0x00, 0x0d); 43 if (ret) 44 return ret; 45 46 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 47 CXD2880_IO_TGT_DMD, 48 0x10, &rdata, 1); 49 if (ret) 50 return ret; 51 52 *unlock_detected = (rdata & 0x10) ? 1 : 0; 53 *sync_stat = rdata & 0x07; 54 *ts_lock_stat = (rdata & 0x20) ? 1 : 0; 55 56 if (*sync_stat == 0x07) 57 return -EAGAIN; 58 59 return ret; 60} 61 62int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd 63 *tnr_dmd, u8 *sync_stat, 64 u8 *unlock_detected) 65{ 66 u8 ts_lock_stat = 0; 67 68 if (!tnr_dmd || !sync_stat || !unlock_detected) 69 return -EINVAL; 70 71 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) 72 return -EINVAL; 73 74 return cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub, 75 sync_stat, 76 &ts_lock_stat, 77 unlock_detected); 78} 79 80int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd 81 *tnr_dmd, 82 enum cxd2880_dvbt_mode 83 *mode, 84 enum cxd2880_dvbt_guard 85 *guard) 86{ 87 u8 rdata = 0x00; 88 int ret; 89 90 if (!tnr_dmd || !mode || !guard) 91 return -EINVAL; 92 93 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 94 return -EINVAL; 95 96 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) 97 return -EINVAL; 98 99 ret = slvt_freeze_reg(tnr_dmd); 100 if (ret) 101 return ret; 102 103 ret = is_tps_locked(tnr_dmd); 104 if (ret) { 105 slvt_unfreeze_reg(tnr_dmd); 106 107 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) 108 ret = 109 cxd2880_tnrdmd_dvbt_mon_mode_guard(tnr_dmd->diver_sub, 110 mode, guard); 111 112 return ret; 113 } 114 115 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 116 CXD2880_IO_TGT_DMD, 117 0x00, 0x0d); 118 if (ret) { 119 slvt_unfreeze_reg(tnr_dmd); 120 return ret; 121 } 122 123 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 124 CXD2880_IO_TGT_DMD, 125 0x1b, &rdata, 1); 126 if (ret) { 127 slvt_unfreeze_reg(tnr_dmd); 128 return ret; 129 } 130 131 slvt_unfreeze_reg(tnr_dmd); 132 133 *mode = (enum cxd2880_dvbt_mode)((rdata >> 2) & 0x03); 134 *guard = (enum cxd2880_dvbt_guard)(rdata & 0x03); 135 136 return ret; 137} 138 139int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd 140 *tnr_dmd, int *offset) 141{ 142 u8 rdata[4]; 143 u32 ctl_val = 0; 144 int ret; 145 146 if (!tnr_dmd || !offset) 147 return -EINVAL; 148 149 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 150 return -EINVAL; 151 152 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) 153 return -EINVAL; 154 155 ret = slvt_freeze_reg(tnr_dmd); 156 if (ret) 157 return ret; 158 159 ret = is_tps_locked(tnr_dmd); 160 if (ret) { 161 slvt_unfreeze_reg(tnr_dmd); 162 return ret; 163 } 164 165 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 166 CXD2880_IO_TGT_DMD, 167 0x00, 0x0d); 168 if (ret) { 169 slvt_unfreeze_reg(tnr_dmd); 170 return ret; 171 } 172 173 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 174 CXD2880_IO_TGT_DMD, 175 0x1d, rdata, 4); 176 if (ret) { 177 slvt_unfreeze_reg(tnr_dmd); 178 return ret; 179 } 180 181 slvt_unfreeze_reg(tnr_dmd); 182 183 ctl_val = 184 ((rdata[0] & 0x1f) << 24) | (rdata[1] << 16) | (rdata[2] << 8) | 185 (rdata[3]); 186 *offset = cxd2880_convert2s_complement(ctl_val, 29); 187 *offset = -1 * ((*offset) * tnr_dmd->bandwidth / 235); 188 189 return ret; 190} 191 192int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct 193 cxd2880_tnrdmd 194 *tnr_dmd, 195 int *offset) 196{ 197 if (!tnr_dmd || !offset) 198 return -EINVAL; 199 200 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) 201 return -EINVAL; 202 203 return cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub, 204 offset); 205} 206 207int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd 208 *tnr_dmd, 209 struct cxd2880_dvbt_tpsinfo 210 *info) 211{ 212 u8 rdata[7]; 213 u8 cell_id_ok = 0; 214 int ret; 215 216 if (!tnr_dmd || !info) 217 return -EINVAL; 218 219 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 220 return -EINVAL; 221 222 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) 223 return -EINVAL; 224 225 ret = slvt_freeze_reg(tnr_dmd); 226 if (ret) 227 return ret; 228 229 ret = is_tps_locked(tnr_dmd); 230 if (ret) { 231 slvt_unfreeze_reg(tnr_dmd); 232 233 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) 234 ret = 235 cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd->diver_sub, 236 info); 237 238 return ret; 239 } 240 241 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 242 CXD2880_IO_TGT_DMD, 243 0x00, 0x0d); 244 if (ret) { 245 slvt_unfreeze_reg(tnr_dmd); 246 return ret; 247 } 248 249 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 250 CXD2880_IO_TGT_DMD, 251 0x29, rdata, 7); 252 if (ret) { 253 slvt_unfreeze_reg(tnr_dmd); 254 return ret; 255 } 256 257 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 258 CXD2880_IO_TGT_DMD, 259 0x00, 0x11); 260 if (ret) { 261 slvt_unfreeze_reg(tnr_dmd); 262 return ret; 263 } 264 265 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 266 CXD2880_IO_TGT_DMD, 267 0xd5, &cell_id_ok, 1); 268 if (ret) { 269 slvt_unfreeze_reg(tnr_dmd); 270 return ret; 271 } 272 273 slvt_unfreeze_reg(tnr_dmd); 274 275 info->constellation = 276 (enum cxd2880_dvbt_constellation)((rdata[0] >> 6) & 0x03); 277 info->hierarchy = (enum cxd2880_dvbt_hierarchy)((rdata[0] >> 3) & 0x07); 278 info->rate_hp = (enum cxd2880_dvbt_coderate)(rdata[0] & 0x07); 279 info->rate_lp = (enum cxd2880_dvbt_coderate)((rdata[1] >> 5) & 0x07); 280 info->guard = (enum cxd2880_dvbt_guard)((rdata[1] >> 3) & 0x03); 281 info->mode = (enum cxd2880_dvbt_mode)((rdata[1] >> 1) & 0x03); 282 info->fnum = (rdata[2] >> 6) & 0x03; 283 info->length_indicator = rdata[2] & 0x3f; 284 info->cell_id = (rdata[3] << 8) | rdata[4]; 285 info->reserved_even = rdata[5] & 0x3f; 286 info->reserved_odd = rdata[6] & 0x3f; 287 288 info->cell_id_ok = cell_id_ok & 0x01; 289 290 return ret; 291} 292 293int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct 294 cxd2880_tnrdmd 295 *tnr_dmd, 296 u32 *pen) 297{ 298 u8 rdata[3]; 299 int ret; 300 301 if (!tnr_dmd || !pen) 302 return -EINVAL; 303 304 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 305 return -EINVAL; 306 307 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 308 return -EINVAL; 309 310 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) 311 return -EINVAL; 312 313 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 314 CXD2880_IO_TGT_DMD, 315 0x00, 0x0d); 316 if (ret) 317 return ret; 318 319 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 320 CXD2880_IO_TGT_DMD, 321 0x26, rdata, 3); 322 if (ret) 323 return ret; 324 325 if (!(rdata[0] & 0x01)) 326 return -EAGAIN; 327 328 *pen = (rdata[1] << 8) | rdata[2]; 329 330 return ret; 331} 332 333int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd 334 *tnr_dmd, 335 enum 336 cxd2880_tnrdmd_spectrum_sense 337 *sense) 338{ 339 u8 data = 0; 340 int ret; 341 342 if (!tnr_dmd || !sense) 343 return -EINVAL; 344 345 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 346 return -EINVAL; 347 348 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) 349 return -EINVAL; 350 351 ret = slvt_freeze_reg(tnr_dmd); 352 if (ret) 353 return ret; 354 355 ret = is_tps_locked(tnr_dmd); 356 if (ret) { 357 slvt_unfreeze_reg(tnr_dmd); 358 359 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) 360 ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(tnr_dmd->diver_sub, 361 sense); 362 363 return ret; 364 } 365 366 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 367 CXD2880_IO_TGT_DMD, 368 0x00, 0x0d); 369 if (ret) { 370 slvt_unfreeze_reg(tnr_dmd); 371 return ret; 372 } 373 374 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 375 CXD2880_IO_TGT_DMD, 376 0x1c, &data, sizeof(data)); 377 if (ret) { 378 slvt_unfreeze_reg(tnr_dmd); 379 return ret; 380 } 381 382 slvt_unfreeze_reg(tnr_dmd); 383 384 *sense = 385 (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV : 386 CXD2880_TNRDMD_SPECTRUM_NORMAL; 387 388 return ret; 389} 390 391static int dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd, 392 u16 *reg_value) 393{ 394 u8 rdata[2]; 395 int ret; 396 397 if (!tnr_dmd || !reg_value) 398 return -EINVAL; 399 400 ret = slvt_freeze_reg(tnr_dmd); 401 if (ret) 402 return ret; 403 404 ret = is_tps_locked(tnr_dmd); 405 if (ret) { 406 slvt_unfreeze_reg(tnr_dmd); 407 return ret; 408 } 409 410 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 411 CXD2880_IO_TGT_DMD, 412 0x00, 0x0d); 413 if (ret) { 414 slvt_unfreeze_reg(tnr_dmd); 415 return ret; 416 } 417 418 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 419 CXD2880_IO_TGT_DMD, 420 0x13, rdata, 2); 421 if (ret) { 422 slvt_unfreeze_reg(tnr_dmd); 423 return ret; 424 } 425 426 slvt_unfreeze_reg(tnr_dmd); 427 428 *reg_value = (rdata[0] << 8) | rdata[1]; 429 430 return ret; 431} 432 433static int dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd, 434 u32 reg_value, int *snr) 435{ 436 if (!tnr_dmd || !snr) 437 return -EINVAL; 438 439 if (reg_value == 0) 440 return -EAGAIN; 441 442 if (reg_value > 4996) 443 reg_value = 4996; 444 445 *snr = intlog10(reg_value) - intlog10(5350 - reg_value); 446 *snr = (*snr + 839) / 1678 + 28500; 447 448 return 0; 449} 450 451int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, 452 int *snr) 453{ 454 u16 reg_value = 0; 455 int ret; 456 457 if (!tnr_dmd || !snr) 458 return -EINVAL; 459 460 *snr = -1000 * 1000; 461 462 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 463 return -EINVAL; 464 465 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 466 return -EINVAL; 467 468 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) 469 return -EINVAL; 470 471 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { 472 ret = dvbt_read_snr_reg(tnr_dmd, ®_value); 473 if (ret) 474 return ret; 475 476 ret = dvbt_calc_snr(tnr_dmd, reg_value, snr); 477 } else { 478 int snr_main = 0; 479 int snr_sub = 0; 480 481 ret = 482 cxd2880_tnrdmd_dvbt_mon_snr_diver(tnr_dmd, snr, &snr_main, 483 &snr_sub); 484 } 485 486 return ret; 487} 488 489int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd 490 *tnr_dmd, int *snr, 491 int *snr_main, int *snr_sub) 492{ 493 u16 reg_value = 0; 494 u32 reg_value_sum = 0; 495 int ret; 496 497 if (!tnr_dmd || !snr || !snr_main || !snr_sub) 498 return -EINVAL; 499 500 *snr = -1000 * 1000; 501 *snr_main = -1000 * 1000; 502 *snr_sub = -1000 * 1000; 503 504 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) 505 return -EINVAL; 506 507 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 508 return -EINVAL; 509 510 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) 511 return -EINVAL; 512 513 ret = dvbt_read_snr_reg(tnr_dmd, ®_value); 514 if (!ret) { 515 ret = dvbt_calc_snr(tnr_dmd, reg_value, snr_main); 516 if (ret) 517 reg_value = 0; 518 } else if (ret == -EAGAIN) { 519 reg_value = 0; 520 } else { 521 return ret; 522 } 523 524 reg_value_sum += reg_value; 525 526 ret = dvbt_read_snr_reg(tnr_dmd->diver_sub, ®_value); 527 if (!ret) { 528 ret = dvbt_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub); 529 if (ret) 530 reg_value = 0; 531 } else if (ret == -EAGAIN) { 532 reg_value = 0; 533 } else { 534 return ret; 535 } 536 537 reg_value_sum += reg_value; 538 539 return dvbt_calc_snr(tnr_dmd, reg_value_sum, snr); 540} 541 542int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd 543 *tnr_dmd, int *ppm) 544{ 545 u8 ctl_val_reg[5]; 546 u8 nominal_rate_reg[5]; 547 u32 trl_ctl_val = 0; 548 u32 trcg_nominal_rate = 0; 549 int num; 550 int den; 551 s8 diff_upper = 0; 552 int ret; 553 554 if (!tnr_dmd || !ppm) 555 return -EINVAL; 556 557 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 558 return -EINVAL; 559 560 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) 561 return -EINVAL; 562 563 ret = slvt_freeze_reg(tnr_dmd); 564 if (ret) 565 return ret; 566 567 ret = is_tps_locked(tnr_dmd); 568 if (ret) { 569 slvt_unfreeze_reg(tnr_dmd); 570 return ret; 571 } 572 573 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 574 CXD2880_IO_TGT_DMD, 575 0x00, 0x0d); 576 if (ret) { 577 slvt_unfreeze_reg(tnr_dmd); 578 return ret; 579 } 580 581 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 582 CXD2880_IO_TGT_DMD, 583 0x21, ctl_val_reg, 584 sizeof(ctl_val_reg)); 585 if (ret) { 586 slvt_unfreeze_reg(tnr_dmd); 587 return ret; 588 } 589 590 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 591 CXD2880_IO_TGT_DMD, 592 0x00, 0x04); 593 if (ret) { 594 slvt_unfreeze_reg(tnr_dmd); 595 return ret; 596 } 597 598 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 599 CXD2880_IO_TGT_DMD, 600 0x60, nominal_rate_reg, 601 sizeof(nominal_rate_reg)); 602 if (ret) { 603 slvt_unfreeze_reg(tnr_dmd); 604 return ret; 605 } 606 607 slvt_unfreeze_reg(tnr_dmd); 608 609 diff_upper = 610 (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f); 611 612 if (diff_upper < -1 || diff_upper > 1) 613 return -EAGAIN; 614 615 trl_ctl_val = ctl_val_reg[1] << 24; 616 trl_ctl_val |= ctl_val_reg[2] << 16; 617 trl_ctl_val |= ctl_val_reg[3] << 8; 618 trl_ctl_val |= ctl_val_reg[4]; 619 620 trcg_nominal_rate = nominal_rate_reg[1] << 24; 621 trcg_nominal_rate |= nominal_rate_reg[2] << 16; 622 trcg_nominal_rate |= nominal_rate_reg[3] << 8; 623 trcg_nominal_rate |= nominal_rate_reg[4]; 624 625 trl_ctl_val >>= 1; 626 trcg_nominal_rate >>= 1; 627 628 if (diff_upper == 1) 629 num = 630 (int)((trl_ctl_val + 0x80000000u) - 631 trcg_nominal_rate); 632 else if (diff_upper == -1) 633 num = 634 -(int)((trcg_nominal_rate + 0x80000000u) - 635 trl_ctl_val); 636 else 637 num = (int)(trl_ctl_val - trcg_nominal_rate); 638 639 den = (nominal_rate_reg[0] & 0x7f) << 24; 640 den |= nominal_rate_reg[1] << 16; 641 den |= nominal_rate_reg[2] << 8; 642 den |= nominal_rate_reg[3]; 643 den = (den + (390625 / 2)) / 390625; 644 645 den >>= 1; 646 647 if (num >= 0) 648 *ppm = (num + (den / 2)) / den; 649 else 650 *ppm = (num - (den / 2)) / den; 651 652 return ret; 653} 654 655int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct 656 cxd2880_tnrdmd 657 *tnr_dmd, int *ppm) 658{ 659 if (!tnr_dmd || !ppm) 660 return -EINVAL; 661 662 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) 663 return -EINVAL; 664 665 return cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm); 666} 667 668static int dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd, 669 int rf_lvl, u8 *ssi) 670{ 671 struct cxd2880_dvbt_tpsinfo tps; 672 int prel; 673 int temp_ssi = 0; 674 int ret; 675 676 if (!tnr_dmd || !ssi) 677 return -EINVAL; 678 679 ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps); 680 if (ret) 681 return ret; 682 683 if (tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3 || 684 tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5) 685 return -EINVAL; 686 687 prel = rf_lvl - ref_dbm_1000[tps.constellation][tps.rate_hp]; 688 689 if (prel < -15000) 690 temp_ssi = 0; 691 else if (prel < 0) 692 temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000; 693 else if (prel < 20000) 694 temp_ssi = (((4 * prel) + 500) / 1000) + 10; 695 else if (prel < 35000) 696 temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90; 697 else 698 temp_ssi = 100; 699 700 *ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi; 701 702 return ret; 703} 704 705int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, 706 u8 *ssi) 707{ 708 int rf_lvl = 0; 709 int ret; 710 711 if (!tnr_dmd || !ssi) 712 return -EINVAL; 713 714 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 715 return -EINVAL; 716 717 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 718 return -EINVAL; 719 720 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) 721 return -EINVAL; 722 723 ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl); 724 if (ret) 725 return ret; 726 727 return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi); 728} 729 730int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd, 731 u8 *ssi) 732{ 733 int rf_lvl = 0; 734 int ret; 735 736 if (!tnr_dmd || !ssi) 737 return -EINVAL; 738 739 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) 740 return -EINVAL; 741 742 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 743 return -EINVAL; 744 745 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) 746 return -EINVAL; 747 748 ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl); 749 if (ret) 750 return ret; 751 752 return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi); 753} 754 755static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd) 756{ 757 u8 sync = 0; 758 u8 tslock = 0; 759 u8 early_unlock = 0; 760 int ret; 761 762 if (!tnr_dmd) 763 return -EINVAL; 764 765 ret = 766 cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync, &tslock, 767 &early_unlock); 768 if (ret) 769 return ret; 770 771 if (sync != 6) 772 return -EAGAIN; 773 774 return 0; 775}