776 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * cxd2880_tnrdmd_dvbt_mon.c4 * Sony CXD2880 DVB-T2/T tuner + demodulator driver5 * DVB-T monitor functions6 *7 * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation8 */9 10#include "cxd2880_tnrdmd_mon.h"11#include "cxd2880_tnrdmd_dvbt.h"12#include "cxd2880_tnrdmd_dvbt_mon.h"13 14#include <linux/int_log.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_tnrdmd25 *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_tnrdmd63 *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_tnrdmd81 *tnr_dmd,82 enum cxd2880_dvbt_mode83 *mode,84 enum cxd2880_dvbt_guard85 *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_tnrdmd140 *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(struct193 cxd2880_tnrdmd194 *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_tnrdmd208 *tnr_dmd,209 struct cxd2880_dvbt_tpsinfo210 *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(struct294 cxd2880_tnrdmd295 *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_tnrdmd334 *tnr_dmd,335 enum336 cxd2880_tnrdmd_spectrum_sense337 *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_tnrdmd490 *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_tnrdmd543 *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 else637 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 else650 *ppm = (num - (den / 2)) / den;651 652 return ret;653}654 655int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct656 cxd2880_tnrdmd657 *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 else698 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}776