0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include "cxd2880_tnrdmd_mon.h"
0011 #include "cxd2880_tnrdmd_dvbt.h"
0012 #include "cxd2880_tnrdmd_dvbt_mon.h"
0013
0014 #include <media/dvb_math.h>
0015
0016 static const int ref_dbm_1000[3][5] = {
0017 {-93000, -91000, -90000, -89000, -88000},
0018 {-87000, -85000, -84000, -83000, -82000},
0019 {-82000, -80000, -78000, -77000, -76000},
0020 };
0021
0022 static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd);
0023
0024 int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
0025 *tnr_dmd, u8 *sync_stat,
0026 u8 *ts_lock_stat,
0027 u8 *unlock_detected)
0028 {
0029 u8 rdata = 0x00;
0030 int ret;
0031
0032 if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected)
0033 return -EINVAL;
0034
0035 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0036 return -EINVAL;
0037 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
0038 return -EINVAL;
0039
0040 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0041 CXD2880_IO_TGT_DMD,
0042 0x00, 0x0d);
0043 if (ret)
0044 return ret;
0045
0046 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0047 CXD2880_IO_TGT_DMD,
0048 0x10, &rdata, 1);
0049 if (ret)
0050 return ret;
0051
0052 *unlock_detected = (rdata & 0x10) ? 1 : 0;
0053 *sync_stat = rdata & 0x07;
0054 *ts_lock_stat = (rdata & 0x20) ? 1 : 0;
0055
0056 if (*sync_stat == 0x07)
0057 return -EAGAIN;
0058
0059 return ret;
0060 }
0061
0062 int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
0063 *tnr_dmd, u8 *sync_stat,
0064 u8 *unlock_detected)
0065 {
0066 u8 ts_lock_stat = 0;
0067
0068 if (!tnr_dmd || !sync_stat || !unlock_detected)
0069 return -EINVAL;
0070
0071 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
0072 return -EINVAL;
0073
0074 return cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub,
0075 sync_stat,
0076 &ts_lock_stat,
0077 unlock_detected);
0078 }
0079
0080 int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
0081 *tnr_dmd,
0082 enum cxd2880_dvbt_mode
0083 *mode,
0084 enum cxd2880_dvbt_guard
0085 *guard)
0086 {
0087 u8 rdata = 0x00;
0088 int ret;
0089
0090 if (!tnr_dmd || !mode || !guard)
0091 return -EINVAL;
0092
0093 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0094 return -EINVAL;
0095
0096 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
0097 return -EINVAL;
0098
0099 ret = slvt_freeze_reg(tnr_dmd);
0100 if (ret)
0101 return ret;
0102
0103 ret = is_tps_locked(tnr_dmd);
0104 if (ret) {
0105 slvt_unfreeze_reg(tnr_dmd);
0106
0107 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
0108 ret =
0109 cxd2880_tnrdmd_dvbt_mon_mode_guard(tnr_dmd->diver_sub,
0110 mode, guard);
0111
0112 return ret;
0113 }
0114
0115 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0116 CXD2880_IO_TGT_DMD,
0117 0x00, 0x0d);
0118 if (ret) {
0119 slvt_unfreeze_reg(tnr_dmd);
0120 return ret;
0121 }
0122
0123 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0124 CXD2880_IO_TGT_DMD,
0125 0x1b, &rdata, 1);
0126 if (ret) {
0127 slvt_unfreeze_reg(tnr_dmd);
0128 return ret;
0129 }
0130
0131 slvt_unfreeze_reg(tnr_dmd);
0132
0133 *mode = (enum cxd2880_dvbt_mode)((rdata >> 2) & 0x03);
0134 *guard = (enum cxd2880_dvbt_guard)(rdata & 0x03);
0135
0136 return ret;
0137 }
0138
0139 int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
0140 *tnr_dmd, int *offset)
0141 {
0142 u8 rdata[4];
0143 u32 ctl_val = 0;
0144 int ret;
0145
0146 if (!tnr_dmd || !offset)
0147 return -EINVAL;
0148
0149 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0150 return -EINVAL;
0151
0152 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
0153 return -EINVAL;
0154
0155 ret = slvt_freeze_reg(tnr_dmd);
0156 if (ret)
0157 return ret;
0158
0159 ret = is_tps_locked(tnr_dmd);
0160 if (ret) {
0161 slvt_unfreeze_reg(tnr_dmd);
0162 return ret;
0163 }
0164
0165 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0166 CXD2880_IO_TGT_DMD,
0167 0x00, 0x0d);
0168 if (ret) {
0169 slvt_unfreeze_reg(tnr_dmd);
0170 return ret;
0171 }
0172
0173 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0174 CXD2880_IO_TGT_DMD,
0175 0x1d, rdata, 4);
0176 if (ret) {
0177 slvt_unfreeze_reg(tnr_dmd);
0178 return ret;
0179 }
0180
0181 slvt_unfreeze_reg(tnr_dmd);
0182
0183 ctl_val =
0184 ((rdata[0] & 0x1f) << 24) | (rdata[1] << 16) | (rdata[2] << 8) |
0185 (rdata[3]);
0186 *offset = cxd2880_convert2s_complement(ctl_val, 29);
0187 *offset = -1 * ((*offset) * tnr_dmd->bandwidth / 235);
0188
0189 return ret;
0190 }
0191
0192 int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
0193 cxd2880_tnrdmd
0194 *tnr_dmd,
0195 int *offset)
0196 {
0197 if (!tnr_dmd || !offset)
0198 return -EINVAL;
0199
0200 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
0201 return -EINVAL;
0202
0203 return cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub,
0204 offset);
0205 }
0206
0207 int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
0208 *tnr_dmd,
0209 struct cxd2880_dvbt_tpsinfo
0210 *info)
0211 {
0212 u8 rdata[7];
0213 u8 cell_id_ok = 0;
0214 int ret;
0215
0216 if (!tnr_dmd || !info)
0217 return -EINVAL;
0218
0219 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0220 return -EINVAL;
0221
0222 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
0223 return -EINVAL;
0224
0225 ret = slvt_freeze_reg(tnr_dmd);
0226 if (ret)
0227 return ret;
0228
0229 ret = is_tps_locked(tnr_dmd);
0230 if (ret) {
0231 slvt_unfreeze_reg(tnr_dmd);
0232
0233 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
0234 ret =
0235 cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd->diver_sub,
0236 info);
0237
0238 return ret;
0239 }
0240
0241 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0242 CXD2880_IO_TGT_DMD,
0243 0x00, 0x0d);
0244 if (ret) {
0245 slvt_unfreeze_reg(tnr_dmd);
0246 return ret;
0247 }
0248
0249 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0250 CXD2880_IO_TGT_DMD,
0251 0x29, rdata, 7);
0252 if (ret) {
0253 slvt_unfreeze_reg(tnr_dmd);
0254 return ret;
0255 }
0256
0257 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0258 CXD2880_IO_TGT_DMD,
0259 0x00, 0x11);
0260 if (ret) {
0261 slvt_unfreeze_reg(tnr_dmd);
0262 return ret;
0263 }
0264
0265 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0266 CXD2880_IO_TGT_DMD,
0267 0xd5, &cell_id_ok, 1);
0268 if (ret) {
0269 slvt_unfreeze_reg(tnr_dmd);
0270 return ret;
0271 }
0272
0273 slvt_unfreeze_reg(tnr_dmd);
0274
0275 info->constellation =
0276 (enum cxd2880_dvbt_constellation)((rdata[0] >> 6) & 0x03);
0277 info->hierarchy = (enum cxd2880_dvbt_hierarchy)((rdata[0] >> 3) & 0x07);
0278 info->rate_hp = (enum cxd2880_dvbt_coderate)(rdata[0] & 0x07);
0279 info->rate_lp = (enum cxd2880_dvbt_coderate)((rdata[1] >> 5) & 0x07);
0280 info->guard = (enum cxd2880_dvbt_guard)((rdata[1] >> 3) & 0x03);
0281 info->mode = (enum cxd2880_dvbt_mode)((rdata[1] >> 1) & 0x03);
0282 info->fnum = (rdata[2] >> 6) & 0x03;
0283 info->length_indicator = rdata[2] & 0x3f;
0284 info->cell_id = (rdata[3] << 8) | rdata[4];
0285 info->reserved_even = rdata[5] & 0x3f;
0286 info->reserved_odd = rdata[6] & 0x3f;
0287
0288 info->cell_id_ok = cell_id_ok & 0x01;
0289
0290 return ret;
0291 }
0292
0293 int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
0294 cxd2880_tnrdmd
0295 *tnr_dmd,
0296 u32 *pen)
0297 {
0298 u8 rdata[3];
0299 int ret;
0300
0301 if (!tnr_dmd || !pen)
0302 return -EINVAL;
0303
0304 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0305 return -EINVAL;
0306
0307 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0308 return -EINVAL;
0309
0310 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
0311 return -EINVAL;
0312
0313 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0314 CXD2880_IO_TGT_DMD,
0315 0x00, 0x0d);
0316 if (ret)
0317 return ret;
0318
0319 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0320 CXD2880_IO_TGT_DMD,
0321 0x26, rdata, 3);
0322 if (ret)
0323 return ret;
0324
0325 if (!(rdata[0] & 0x01))
0326 return -EAGAIN;
0327
0328 *pen = (rdata[1] << 8) | rdata[2];
0329
0330 return ret;
0331 }
0332
0333 int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
0334 *tnr_dmd,
0335 enum
0336 cxd2880_tnrdmd_spectrum_sense
0337 *sense)
0338 {
0339 u8 data = 0;
0340 int ret;
0341
0342 if (!tnr_dmd || !sense)
0343 return -EINVAL;
0344
0345 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0346 return -EINVAL;
0347
0348 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
0349 return -EINVAL;
0350
0351 ret = slvt_freeze_reg(tnr_dmd);
0352 if (ret)
0353 return ret;
0354
0355 ret = is_tps_locked(tnr_dmd);
0356 if (ret) {
0357 slvt_unfreeze_reg(tnr_dmd);
0358
0359 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
0360 ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(tnr_dmd->diver_sub,
0361 sense);
0362
0363 return ret;
0364 }
0365
0366 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0367 CXD2880_IO_TGT_DMD,
0368 0x00, 0x0d);
0369 if (ret) {
0370 slvt_unfreeze_reg(tnr_dmd);
0371 return ret;
0372 }
0373
0374 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0375 CXD2880_IO_TGT_DMD,
0376 0x1c, &data, sizeof(data));
0377 if (ret) {
0378 slvt_unfreeze_reg(tnr_dmd);
0379 return ret;
0380 }
0381
0382 slvt_unfreeze_reg(tnr_dmd);
0383
0384 *sense =
0385 (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
0386 CXD2880_TNRDMD_SPECTRUM_NORMAL;
0387
0388 return ret;
0389 }
0390
0391 static int dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
0392 u16 *reg_value)
0393 {
0394 u8 rdata[2];
0395 int ret;
0396
0397 if (!tnr_dmd || !reg_value)
0398 return -EINVAL;
0399
0400 ret = slvt_freeze_reg(tnr_dmd);
0401 if (ret)
0402 return ret;
0403
0404 ret = is_tps_locked(tnr_dmd);
0405 if (ret) {
0406 slvt_unfreeze_reg(tnr_dmd);
0407 return ret;
0408 }
0409
0410 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0411 CXD2880_IO_TGT_DMD,
0412 0x00, 0x0d);
0413 if (ret) {
0414 slvt_unfreeze_reg(tnr_dmd);
0415 return ret;
0416 }
0417
0418 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0419 CXD2880_IO_TGT_DMD,
0420 0x13, rdata, 2);
0421 if (ret) {
0422 slvt_unfreeze_reg(tnr_dmd);
0423 return ret;
0424 }
0425
0426 slvt_unfreeze_reg(tnr_dmd);
0427
0428 *reg_value = (rdata[0] << 8) | rdata[1];
0429
0430 return ret;
0431 }
0432
0433 static int dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
0434 u32 reg_value, int *snr)
0435 {
0436 if (!tnr_dmd || !snr)
0437 return -EINVAL;
0438
0439 if (reg_value == 0)
0440 return -EAGAIN;
0441
0442 if (reg_value > 4996)
0443 reg_value = 4996;
0444
0445 *snr = intlog10(reg_value) - intlog10(5350 - reg_value);
0446 *snr = (*snr + 839) / 1678 + 28500;
0447
0448 return 0;
0449 }
0450
0451 int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
0452 int *snr)
0453 {
0454 u16 reg_value = 0;
0455 int ret;
0456
0457 if (!tnr_dmd || !snr)
0458 return -EINVAL;
0459
0460 *snr = -1000 * 1000;
0461
0462 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0463 return -EINVAL;
0464
0465 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0466 return -EINVAL;
0467
0468 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
0469 return -EINVAL;
0470
0471 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
0472 ret = dvbt_read_snr_reg(tnr_dmd, ®_value);
0473 if (ret)
0474 return ret;
0475
0476 ret = dvbt_calc_snr(tnr_dmd, reg_value, snr);
0477 } else {
0478 int snr_main = 0;
0479 int snr_sub = 0;
0480
0481 ret =
0482 cxd2880_tnrdmd_dvbt_mon_snr_diver(tnr_dmd, snr, &snr_main,
0483 &snr_sub);
0484 }
0485
0486 return ret;
0487 }
0488
0489 int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
0490 *tnr_dmd, int *snr,
0491 int *snr_main, int *snr_sub)
0492 {
0493 u16 reg_value = 0;
0494 u32 reg_value_sum = 0;
0495 int ret;
0496
0497 if (!tnr_dmd || !snr || !snr_main || !snr_sub)
0498 return -EINVAL;
0499
0500 *snr = -1000 * 1000;
0501 *snr_main = -1000 * 1000;
0502 *snr_sub = -1000 * 1000;
0503
0504 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
0505 return -EINVAL;
0506
0507 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0508 return -EINVAL;
0509
0510 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
0511 return -EINVAL;
0512
0513 ret = dvbt_read_snr_reg(tnr_dmd, ®_value);
0514 if (!ret) {
0515 ret = dvbt_calc_snr(tnr_dmd, reg_value, snr_main);
0516 if (ret)
0517 reg_value = 0;
0518 } else if (ret == -EAGAIN) {
0519 reg_value = 0;
0520 } else {
0521 return ret;
0522 }
0523
0524 reg_value_sum += reg_value;
0525
0526 ret = dvbt_read_snr_reg(tnr_dmd->diver_sub, ®_value);
0527 if (!ret) {
0528 ret = dvbt_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
0529 if (ret)
0530 reg_value = 0;
0531 } else if (ret == -EAGAIN) {
0532 reg_value = 0;
0533 } else {
0534 return ret;
0535 }
0536
0537 reg_value_sum += reg_value;
0538
0539 return dvbt_calc_snr(tnr_dmd, reg_value_sum, snr);
0540 }
0541
0542 int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
0543 *tnr_dmd, int *ppm)
0544 {
0545 u8 ctl_val_reg[5];
0546 u8 nominal_rate_reg[5];
0547 u32 trl_ctl_val = 0;
0548 u32 trcg_nominal_rate = 0;
0549 int num;
0550 int den;
0551 s8 diff_upper = 0;
0552 int ret;
0553
0554 if (!tnr_dmd || !ppm)
0555 return -EINVAL;
0556
0557 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0558 return -EINVAL;
0559
0560 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
0561 return -EINVAL;
0562
0563 ret = slvt_freeze_reg(tnr_dmd);
0564 if (ret)
0565 return ret;
0566
0567 ret = is_tps_locked(tnr_dmd);
0568 if (ret) {
0569 slvt_unfreeze_reg(tnr_dmd);
0570 return ret;
0571 }
0572
0573 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0574 CXD2880_IO_TGT_DMD,
0575 0x00, 0x0d);
0576 if (ret) {
0577 slvt_unfreeze_reg(tnr_dmd);
0578 return ret;
0579 }
0580
0581 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0582 CXD2880_IO_TGT_DMD,
0583 0x21, ctl_val_reg,
0584 sizeof(ctl_val_reg));
0585 if (ret) {
0586 slvt_unfreeze_reg(tnr_dmd);
0587 return ret;
0588 }
0589
0590 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0591 CXD2880_IO_TGT_DMD,
0592 0x00, 0x04);
0593 if (ret) {
0594 slvt_unfreeze_reg(tnr_dmd);
0595 return ret;
0596 }
0597
0598 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
0599 CXD2880_IO_TGT_DMD,
0600 0x60, nominal_rate_reg,
0601 sizeof(nominal_rate_reg));
0602 if (ret) {
0603 slvt_unfreeze_reg(tnr_dmd);
0604 return ret;
0605 }
0606
0607 slvt_unfreeze_reg(tnr_dmd);
0608
0609 diff_upper =
0610 (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f);
0611
0612 if (diff_upper < -1 || diff_upper > 1)
0613 return -EAGAIN;
0614
0615 trl_ctl_val = ctl_val_reg[1] << 24;
0616 trl_ctl_val |= ctl_val_reg[2] << 16;
0617 trl_ctl_val |= ctl_val_reg[3] << 8;
0618 trl_ctl_val |= ctl_val_reg[4];
0619
0620 trcg_nominal_rate = nominal_rate_reg[1] << 24;
0621 trcg_nominal_rate |= nominal_rate_reg[2] << 16;
0622 trcg_nominal_rate |= nominal_rate_reg[3] << 8;
0623 trcg_nominal_rate |= nominal_rate_reg[4];
0624
0625 trl_ctl_val >>= 1;
0626 trcg_nominal_rate >>= 1;
0627
0628 if (diff_upper == 1)
0629 num =
0630 (int)((trl_ctl_val + 0x80000000u) -
0631 trcg_nominal_rate);
0632 else if (diff_upper == -1)
0633 num =
0634 -(int)((trcg_nominal_rate + 0x80000000u) -
0635 trl_ctl_val);
0636 else
0637 num = (int)(trl_ctl_val - trcg_nominal_rate);
0638
0639 den = (nominal_rate_reg[0] & 0x7f) << 24;
0640 den |= nominal_rate_reg[1] << 16;
0641 den |= nominal_rate_reg[2] << 8;
0642 den |= nominal_rate_reg[3];
0643 den = (den + (390625 / 2)) / 390625;
0644
0645 den >>= 1;
0646
0647 if (num >= 0)
0648 *ppm = (num + (den / 2)) / den;
0649 else
0650 *ppm = (num - (den / 2)) / den;
0651
0652 return ret;
0653 }
0654
0655 int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
0656 cxd2880_tnrdmd
0657 *tnr_dmd, int *ppm)
0658 {
0659 if (!tnr_dmd || !ppm)
0660 return -EINVAL;
0661
0662 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
0663 return -EINVAL;
0664
0665 return cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm);
0666 }
0667
0668 static int dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
0669 int rf_lvl, u8 *ssi)
0670 {
0671 struct cxd2880_dvbt_tpsinfo tps;
0672 int prel;
0673 int temp_ssi = 0;
0674 int ret;
0675
0676 if (!tnr_dmd || !ssi)
0677 return -EINVAL;
0678
0679 ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps);
0680 if (ret)
0681 return ret;
0682
0683 if (tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3 ||
0684 tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5)
0685 return -EINVAL;
0686
0687 prel = rf_lvl - ref_dbm_1000[tps.constellation][tps.rate_hp];
0688
0689 if (prel < -15000)
0690 temp_ssi = 0;
0691 else if (prel < 0)
0692 temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
0693 else if (prel < 20000)
0694 temp_ssi = (((4 * prel) + 500) / 1000) + 10;
0695 else if (prel < 35000)
0696 temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
0697 else
0698 temp_ssi = 100;
0699
0700 *ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
0701
0702 return ret;
0703 }
0704
0705 int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
0706 u8 *ssi)
0707 {
0708 int rf_lvl = 0;
0709 int ret;
0710
0711 if (!tnr_dmd || !ssi)
0712 return -EINVAL;
0713
0714 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0715 return -EINVAL;
0716
0717 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0718 return -EINVAL;
0719
0720 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
0721 return -EINVAL;
0722
0723 ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
0724 if (ret)
0725 return ret;
0726
0727 return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
0728 }
0729
0730 int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
0731 u8 *ssi)
0732 {
0733 int rf_lvl = 0;
0734 int ret;
0735
0736 if (!tnr_dmd || !ssi)
0737 return -EINVAL;
0738
0739 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
0740 return -EINVAL;
0741
0742 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0743 return -EINVAL;
0744
0745 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
0746 return -EINVAL;
0747
0748 ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
0749 if (ret)
0750 return ret;
0751
0752 return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
0753 }
0754
0755 static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd)
0756 {
0757 u8 sync = 0;
0758 u8 tslock = 0;
0759 u8 early_unlock = 0;
0760 int ret;
0761
0762 if (!tnr_dmd)
0763 return -EINVAL;
0764
0765 ret =
0766 cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync, &tslock,
0767 &early_unlock);
0768 if (ret)
0769 return ret;
0770
0771 if (sync != 6)
0772 return -EAGAIN;
0773
0774 return 0;
0775 }