1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * cxd2880_tnrdmd_dvbt2_mon.c 4 * Sony CXD2880 DVB-T2/T tuner + demodulator driver 5 * DVB-T2 monitor functions 6 * 7 * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation 8 */ 9 10 #include "cxd2880_tnrdmd_mon.h" 11 #include "cxd2880_tnrdmd_dvbt2.h" 12 #include "cxd2880_tnrdmd_dvbt2_mon.h" 13 14 #include <media/dvb_math.h> 15 16 static 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 23 int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd 24 *tnr_dmd, u8 *sync_stat, 25 u8 *ts_lock_stat, 26 u8 *unlock_detected) 27 { 28 u8 data; 29 int ret; 30 31 if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected) 32 return -EINVAL; 33 34 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 35 return -EINVAL; 36 37 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 38 return -EINVAL; 39 40 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 41 CXD2880_IO_TGT_DMD, 42 0x00, 0x0b); 43 if (ret) 44 return ret; 45 46 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 47 CXD2880_IO_TGT_DMD, 48 0x10, &data, sizeof(data)); 49 if (ret) 50 return ret; 51 52 *sync_stat = data & 0x07; 53 *ts_lock_stat = ((data & 0x20) ? 1 : 0); 54 *unlock_detected = ((data & 0x10) ? 1 : 0); 55 56 if (*sync_stat == 0x07) 57 return -EAGAIN; 58 59 return 0; 60 } 61 62 int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd 63 *tnr_dmd, 64 u8 *sync_stat, 65 u8 *unlock_detected) 66 { 67 u8 ts_lock_stat = 0; 68 69 if (!tnr_dmd || !sync_stat || !unlock_detected) 70 return -EINVAL; 71 72 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) 73 return -EINVAL; 74 75 return cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub, 76 sync_stat, 77 &ts_lock_stat, 78 unlock_detected); 79 } 80 81 int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd 82 *tnr_dmd, int *offset) 83 { 84 u8 data[4]; 85 u32 ctl_val = 0; 86 u8 sync_state = 0; 87 u8 ts_lock = 0; 88 u8 unlock_detected = 0; 89 int ret; 90 91 if (!tnr_dmd || !offset) 92 return -EINVAL; 93 94 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 95 return -EINVAL; 96 97 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 98 return -EINVAL; 99 100 ret = slvt_freeze_reg(tnr_dmd); 101 if (ret) 102 return ret; 103 104 ret = 105 cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, 106 &ts_lock, 107 &unlock_detected); 108 if (ret) { 109 slvt_unfreeze_reg(tnr_dmd); 110 return ret; 111 } 112 113 if (sync_state != 6) { 114 slvt_unfreeze_reg(tnr_dmd); 115 return -EAGAIN; 116 } 117 118 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 119 CXD2880_IO_TGT_DMD, 120 0x00, 0x0b); 121 if (ret) { 122 slvt_unfreeze_reg(tnr_dmd); 123 return ret; 124 } 125 126 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 127 CXD2880_IO_TGT_DMD, 128 0x30, data, sizeof(data)); 129 if (ret) { 130 slvt_unfreeze_reg(tnr_dmd); 131 return ret; 132 } 133 134 slvt_unfreeze_reg(tnr_dmd); 135 136 ctl_val = 137 ((data[0] & 0x0f) << 24) | (data[1] << 16) | (data[2] << 8) 138 | (data[3]); 139 *offset = cxd2880_convert2s_complement(ctl_val, 28); 140 141 switch (tnr_dmd->bandwidth) { 142 case CXD2880_DTV_BW_1_7_MHZ: 143 *offset = -1 * ((*offset) / 582); 144 break; 145 case CXD2880_DTV_BW_5_MHZ: 146 case CXD2880_DTV_BW_6_MHZ: 147 case CXD2880_DTV_BW_7_MHZ: 148 case CXD2880_DTV_BW_8_MHZ: 149 *offset = -1 * ((*offset) * tnr_dmd->bandwidth / 940); 150 break; 151 default: 152 return -EINVAL; 153 } 154 155 return 0; 156 } 157 158 int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct 159 cxd2880_tnrdmd 160 *tnr_dmd, 161 int *offset) 162 { 163 if (!tnr_dmd || !offset) 164 return -EINVAL; 165 166 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) 167 return -EINVAL; 168 169 return cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub, 170 offset); 171 } 172 173 int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd, 174 struct cxd2880_dvbt2_l1pre 175 *l1_pre) 176 { 177 u8 data[37]; 178 u8 sync_state = 0; 179 u8 ts_lock = 0; 180 u8 unlock_detected = 0; 181 u8 version = 0; 182 enum cxd2880_dvbt2_profile profile; 183 int ret; 184 185 if (!tnr_dmd || !l1_pre) 186 return -EINVAL; 187 188 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 189 return -EINVAL; 190 191 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 192 return -EINVAL; 193 194 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 195 return -EINVAL; 196 197 ret = slvt_freeze_reg(tnr_dmd); 198 if (ret) 199 return ret; 200 201 ret = 202 cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, 203 &ts_lock, 204 &unlock_detected); 205 if (ret) { 206 slvt_unfreeze_reg(tnr_dmd); 207 return ret; 208 } 209 210 if (sync_state < 5) { 211 if (tnr_dmd->diver_mode == 212 CXD2880_TNRDMD_DIVERMODE_MAIN) { 213 ret = 214 cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub 215 (tnr_dmd, &sync_state, &unlock_detected); 216 if (ret) { 217 slvt_unfreeze_reg(tnr_dmd); 218 return ret; 219 } 220 221 if (sync_state < 5) { 222 slvt_unfreeze_reg(tnr_dmd); 223 return -EAGAIN; 224 } 225 } else { 226 slvt_unfreeze_reg(tnr_dmd); 227 return -EAGAIN; 228 } 229 } 230 231 ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile); 232 if (ret) { 233 slvt_unfreeze_reg(tnr_dmd); 234 return ret; 235 } 236 237 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 238 CXD2880_IO_TGT_DMD, 239 0x00, 0x0b); 240 if (ret) { 241 slvt_unfreeze_reg(tnr_dmd); 242 return ret; 243 } 244 245 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 246 CXD2880_IO_TGT_DMD, 247 0x61, data, sizeof(data)); 248 if (ret) { 249 slvt_unfreeze_reg(tnr_dmd); 250 return ret; 251 } 252 slvt_unfreeze_reg(tnr_dmd); 253 254 l1_pre->type = (enum cxd2880_dvbt2_l1pre_type)data[0]; 255 l1_pre->bw_ext = data[1] & 0x01; 256 l1_pre->s1 = (enum cxd2880_dvbt2_s1)(data[2] & 0x07); 257 l1_pre->s2 = data[3] & 0x0f; 258 l1_pre->l1_rep = data[4] & 0x01; 259 l1_pre->gi = (enum cxd2880_dvbt2_guard)(data[5] & 0x07); 260 l1_pre->papr = (enum cxd2880_dvbt2_papr)(data[6] & 0x0f); 261 l1_pre->mod = 262 (enum cxd2880_dvbt2_l1post_constell)(data[7] & 0x0f); 263 l1_pre->cr = (enum cxd2880_dvbt2_l1post_cr)(data[8] & 0x03); 264 l1_pre->fec = 265 (enum cxd2880_dvbt2_l1post_fec_type)(data[9] & 0x03); 266 l1_pre->l1_post_size = (data[10] & 0x03) << 16; 267 l1_pre->l1_post_size |= (data[11]) << 8; 268 l1_pre->l1_post_size |= (data[12]); 269 l1_pre->l1_post_info_size = (data[13] & 0x03) << 16; 270 l1_pre->l1_post_info_size |= (data[14]) << 8; 271 l1_pre->l1_post_info_size |= (data[15]); 272 l1_pre->pp = (enum cxd2880_dvbt2_pp)(data[16] & 0x0f); 273 l1_pre->tx_id_availability = data[17]; 274 l1_pre->cell_id = (data[18] << 8); 275 l1_pre->cell_id |= (data[19]); 276 l1_pre->network_id = (data[20] << 8); 277 l1_pre->network_id |= (data[21]); 278 l1_pre->sys_id = (data[22] << 8); 279 l1_pre->sys_id |= (data[23]); 280 l1_pre->num_frames = data[24]; 281 l1_pre->num_symbols = (data[25] & 0x0f) << 8; 282 l1_pre->num_symbols |= data[26]; 283 l1_pre->regen = data[27] & 0x07; 284 l1_pre->post_ext = data[28] & 0x01; 285 l1_pre->num_rf_freqs = data[29] & 0x07; 286 l1_pre->rf_idx = data[30] & 0x07; 287 version = (data[31] & 0x03) << 2; 288 version |= (data[32] & 0xc0) >> 6; 289 l1_pre->t2_version = (enum cxd2880_dvbt2_version)version; 290 l1_pre->l1_post_scrambled = (data[32] & 0x20) >> 5; 291 l1_pre->t2_base_lite = (data[32] & 0x10) >> 4; 292 l1_pre->crc32 = (data[33] << 24); 293 l1_pre->crc32 |= (data[34] << 16); 294 l1_pre->crc32 |= (data[35] << 8); 295 l1_pre->crc32 |= data[36]; 296 297 if (profile == CXD2880_DVBT2_PROFILE_BASE) { 298 switch ((l1_pre->s2 >> 1)) { 299 case CXD2880_DVBT2_BASE_S2_M1K_G_ANY: 300 l1_pre->fft_mode = CXD2880_DVBT2_M1K; 301 break; 302 case CXD2880_DVBT2_BASE_S2_M2K_G_ANY: 303 l1_pre->fft_mode = CXD2880_DVBT2_M2K; 304 break; 305 case CXD2880_DVBT2_BASE_S2_M4K_G_ANY: 306 l1_pre->fft_mode = CXD2880_DVBT2_M4K; 307 break; 308 case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT: 309 case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2: 310 l1_pre->fft_mode = CXD2880_DVBT2_M8K; 311 break; 312 case CXD2880_DVBT2_BASE_S2_M16K_G_ANY: 313 l1_pre->fft_mode = CXD2880_DVBT2_M16K; 314 break; 315 case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT: 316 case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2: 317 l1_pre->fft_mode = CXD2880_DVBT2_M32K; 318 break; 319 default: 320 return -EAGAIN; 321 } 322 } else if (profile == CXD2880_DVBT2_PROFILE_LITE) { 323 switch ((l1_pre->s2 >> 1)) { 324 case CXD2880_DVBT2_LITE_S2_M2K_G_ANY: 325 l1_pre->fft_mode = CXD2880_DVBT2_M2K; 326 break; 327 case CXD2880_DVBT2_LITE_S2_M4K_G_ANY: 328 l1_pre->fft_mode = CXD2880_DVBT2_M4K; 329 break; 330 case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT: 331 case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2: 332 l1_pre->fft_mode = CXD2880_DVBT2_M8K; 333 break; 334 case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT: 335 case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2: 336 l1_pre->fft_mode = CXD2880_DVBT2_M16K; 337 break; 338 default: 339 return -EAGAIN; 340 } 341 } else { 342 return -EAGAIN; 343 } 344 345 l1_pre->mixed = l1_pre->s2 & 0x01; 346 347 return ret; 348 } 349 350 int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd 351 *tnr_dmd, 352 enum cxd2880_dvbt2_version 353 *ver) 354 { 355 u8 data[2]; 356 u8 sync_state = 0; 357 u8 ts_lock = 0; 358 u8 unlock_detected = 0; 359 u8 version = 0; 360 int ret; 361 362 if (!tnr_dmd || !ver) 363 return -EINVAL; 364 365 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 366 return -EINVAL; 367 368 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 369 return -EINVAL; 370 371 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 372 return -EINVAL; 373 374 ret = slvt_freeze_reg(tnr_dmd); 375 if (ret) 376 return ret; 377 378 ret = 379 cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, 380 &ts_lock, 381 &unlock_detected); 382 if (ret) { 383 slvt_unfreeze_reg(tnr_dmd); 384 return ret; 385 } 386 387 if (sync_state < 5) { 388 if (tnr_dmd->diver_mode == 389 CXD2880_TNRDMD_DIVERMODE_MAIN) { 390 ret = 391 cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub 392 (tnr_dmd, &sync_state, &unlock_detected); 393 if (ret) { 394 slvt_unfreeze_reg(tnr_dmd); 395 return ret; 396 } 397 398 if (sync_state < 5) { 399 slvt_unfreeze_reg(tnr_dmd); 400 return -EAGAIN; 401 } 402 } else { 403 slvt_unfreeze_reg(tnr_dmd); 404 return -EAGAIN; 405 } 406 } 407 408 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 409 CXD2880_IO_TGT_DMD, 410 0x00, 0x0b); 411 if (ret) { 412 slvt_unfreeze_reg(tnr_dmd); 413 return ret; 414 } 415 416 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 417 CXD2880_IO_TGT_DMD, 418 0x80, data, sizeof(data)); 419 if (ret) { 420 slvt_unfreeze_reg(tnr_dmd); 421 return ret; 422 } 423 424 slvt_unfreeze_reg(tnr_dmd); 425 426 version = ((data[0] & 0x03) << 2); 427 version |= ((data[1] & 0xc0) >> 6); 428 *ver = (enum cxd2880_dvbt2_version)version; 429 430 return ret; 431 } 432 433 int 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 508 int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd 509 *tnr_dmd, u8 *plp_ids, 510 u8 *num_plps) 511 { 512 u8 l1_post_ok = 0; 513 int ret; 514 515 if (!tnr_dmd || !num_plps) 516 return -EINVAL; 517 518 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 519 return -EINVAL; 520 521 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 522 return -EINVAL; 523 524 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 525 return -EINVAL; 526 527 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 528 CXD2880_IO_TGT_DMD, 529 0x00, 0x0b); 530 if (ret) 531 return ret; 532 533 ret = slvt_freeze_reg(tnr_dmd); 534 if (ret) 535 return ret; 536 537 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 538 CXD2880_IO_TGT_DMD, 539 0x86, &l1_post_ok, 1); 540 if (ret) { 541 slvt_unfreeze_reg(tnr_dmd); 542 return ret; 543 } 544 545 if (!(l1_post_ok & 0x01)) { 546 slvt_unfreeze_reg(tnr_dmd); 547 return -EAGAIN; 548 } 549 550 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 551 CXD2880_IO_TGT_DMD, 552 0xc1, num_plps, 1); 553 if (ret) { 554 slvt_unfreeze_reg(tnr_dmd); 555 return ret; 556 } 557 558 if (*num_plps == 0) { 559 slvt_unfreeze_reg(tnr_dmd); 560 return -EINVAL; 561 } 562 563 if (!plp_ids) { 564 slvt_unfreeze_reg(tnr_dmd); 565 return 0; 566 } 567 568 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 569 CXD2880_IO_TGT_DMD, 570 0xc2, 571 plp_ids, 572 ((*num_plps > 62) ? 573 62 : *num_plps)); 574 if (ret) { 575 slvt_unfreeze_reg(tnr_dmd); 576 return ret; 577 } 578 579 if (*num_plps > 62) { 580 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 581 CXD2880_IO_TGT_DMD, 582 0x00, 0x0c); 583 if (ret) { 584 slvt_unfreeze_reg(tnr_dmd); 585 return ret; 586 } 587 588 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 589 CXD2880_IO_TGT_DMD, 590 0x10, plp_ids + 62, 591 *num_plps - 62); 592 if (ret) { 593 slvt_unfreeze_reg(tnr_dmd); 594 return ret; 595 } 596 } 597 598 slvt_unfreeze_reg(tnr_dmd); 599 600 return 0; 601 } 602 603 int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd 604 *tnr_dmd, 605 enum 606 cxd2880_dvbt2_plp_btype 607 type, 608 struct cxd2880_dvbt2_plp 609 *plp_info) 610 { 611 u8 data[20]; 612 u8 addr = 0; 613 u8 index = 0; 614 u8 l1_post_ok = 0; 615 int ret; 616 617 if (!tnr_dmd || !plp_info) 618 return -EINVAL; 619 620 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 621 return -EINVAL; 622 623 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 624 return -EINVAL; 625 626 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 627 return -EINVAL; 628 629 ret = slvt_freeze_reg(tnr_dmd); 630 if (ret) 631 return ret; 632 633 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 634 CXD2880_IO_TGT_DMD, 635 0x00, 0x0b); 636 if (ret) { 637 slvt_unfreeze_reg(tnr_dmd); 638 return ret; 639 } 640 641 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 642 CXD2880_IO_TGT_DMD, 643 0x86, &l1_post_ok, 1); 644 if (ret) { 645 slvt_unfreeze_reg(tnr_dmd); 646 return ret; 647 } 648 649 if (!l1_post_ok) { 650 slvt_unfreeze_reg(tnr_dmd); 651 return -EAGAIN; 652 } 653 654 if (type == CXD2880_DVBT2_PLP_COMMON) 655 addr = 0xa9; 656 else 657 addr = 0x96; 658 659 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 660 CXD2880_IO_TGT_DMD, 661 addr, data, sizeof(data)); 662 if (ret) { 663 slvt_unfreeze_reg(tnr_dmd); 664 return ret; 665 } 666 667 slvt_unfreeze_reg(tnr_dmd); 668 669 if (type == CXD2880_DVBT2_PLP_COMMON && !data[13]) 670 return -EAGAIN; 671 672 plp_info->id = data[index++]; 673 plp_info->type = 674 (enum cxd2880_dvbt2_plp_type)(data[index++] & 0x07); 675 plp_info->payload = 676 (enum cxd2880_dvbt2_plp_payload)(data[index++] & 0x1f); 677 plp_info->ff = data[index++] & 0x01; 678 plp_info->first_rf_idx = data[index++] & 0x07; 679 plp_info->first_frm_idx = data[index++]; 680 plp_info->group_id = data[index++]; 681 plp_info->plp_cr = 682 (enum cxd2880_dvbt2_plp_code_rate)(data[index++] & 0x07); 683 plp_info->constell = 684 (enum cxd2880_dvbt2_plp_constell)(data[index++] & 0x07); 685 plp_info->rot = data[index++] & 0x01; 686 plp_info->fec = 687 (enum cxd2880_dvbt2_plp_fec)(data[index++] & 0x03); 688 plp_info->num_blocks_max = (data[index++] & 0x03) << 8; 689 plp_info->num_blocks_max |= data[index++]; 690 plp_info->frm_int = data[index++]; 691 plp_info->til_len = data[index++]; 692 plp_info->til_type = data[index++] & 0x01; 693 694 plp_info->in_band_a_flag = data[index++] & 0x01; 695 plp_info->rsvd = data[index++] << 8; 696 plp_info->rsvd |= data[index++]; 697 698 plp_info->in_band_b_flag = 699 (plp_info->rsvd & 0x8000) >> 15; 700 plp_info->plp_mode = 701 (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000c) >> 2); 702 plp_info->static_flag = (plp_info->rsvd & 0x0002) >> 1; 703 plp_info->static_padding_flag = plp_info->rsvd & 0x0001; 704 plp_info->rsvd = (plp_info->rsvd & 0x7ff0) >> 4; 705 706 return 0; 707 } 708 709 int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd 710 *tnr_dmd, 711 u8 *plp_error) 712 { 713 u8 data; 714 int ret; 715 716 if (!tnr_dmd || !plp_error) 717 return -EINVAL; 718 719 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 720 return -EINVAL; 721 722 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 723 return -EINVAL; 724 725 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 726 return -EINVAL; 727 728 ret = slvt_freeze_reg(tnr_dmd); 729 if (ret) 730 return ret; 731 732 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 733 CXD2880_IO_TGT_DMD, 734 0x00, 0x0b); 735 if (ret) { 736 slvt_unfreeze_reg(tnr_dmd); 737 return ret; 738 } 739 740 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 741 CXD2880_IO_TGT_DMD, 742 0x86, &data, 1); 743 if (ret) { 744 slvt_unfreeze_reg(tnr_dmd); 745 return ret; 746 } 747 748 if ((data & 0x01) == 0x00) { 749 slvt_unfreeze_reg(tnr_dmd); 750 return -EAGAIN; 751 } 752 753 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 754 CXD2880_IO_TGT_DMD, 755 0xc0, &data, 1); 756 if (ret) { 757 slvt_unfreeze_reg(tnr_dmd); 758 return ret; 759 } 760 761 slvt_unfreeze_reg(tnr_dmd); 762 763 *plp_error = data & 0x01; 764 765 return 0; 766 } 767 768 int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd 769 *tnr_dmd, u8 *l1_change) 770 { 771 u8 data; 772 u8 sync_state = 0; 773 u8 ts_lock = 0; 774 u8 unlock_detected = 0; 775 int ret; 776 777 if (!tnr_dmd || !l1_change) 778 return -EINVAL; 779 780 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 781 return -EINVAL; 782 783 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 784 return -EINVAL; 785 786 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 787 return -EINVAL; 788 789 ret = slvt_freeze_reg(tnr_dmd); 790 if (ret) 791 return ret; 792 793 ret = 794 cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, 795 &ts_lock, 796 &unlock_detected); 797 if (ret) { 798 slvt_unfreeze_reg(tnr_dmd); 799 return ret; 800 } 801 802 if (sync_state < 5) { 803 if (tnr_dmd->diver_mode == 804 CXD2880_TNRDMD_DIVERMODE_MAIN) { 805 ret = 806 cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub 807 (tnr_dmd, &sync_state, &unlock_detected); 808 if (ret) { 809 slvt_unfreeze_reg(tnr_dmd); 810 return ret; 811 } 812 813 if (sync_state < 5) { 814 slvt_unfreeze_reg(tnr_dmd); 815 return -EAGAIN; 816 } 817 } else { 818 slvt_unfreeze_reg(tnr_dmd); 819 return -EAGAIN; 820 } 821 } 822 823 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 824 CXD2880_IO_TGT_DMD, 825 0x00, 0x0b); 826 if (ret) { 827 slvt_unfreeze_reg(tnr_dmd); 828 return ret; 829 } 830 831 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 832 CXD2880_IO_TGT_DMD, 833 0x5f, &data, sizeof(data)); 834 if (ret) { 835 slvt_unfreeze_reg(tnr_dmd); 836 return ret; 837 } 838 839 *l1_change = data & 0x01; 840 if (*l1_change) { 841 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 842 CXD2880_IO_TGT_DMD, 843 0x00, 0x22); 844 if (ret) { 845 slvt_unfreeze_reg(tnr_dmd); 846 return ret; 847 } 848 849 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 850 CXD2880_IO_TGT_DMD, 851 0x16, 0x01); 852 if (ret) { 853 slvt_unfreeze_reg(tnr_dmd); 854 return ret; 855 } 856 } 857 slvt_unfreeze_reg(tnr_dmd); 858 859 return 0; 860 } 861 862 int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd 863 *tnr_dmd, 864 struct cxd2880_dvbt2_l1post 865 *l1_post) 866 { 867 u8 data[16]; 868 int ret; 869 870 if (!tnr_dmd || !l1_post) 871 return -EINVAL; 872 873 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 874 return -EINVAL; 875 876 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 877 return -EINVAL; 878 879 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 880 return -EINVAL; 881 882 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 883 CXD2880_IO_TGT_DMD, 884 0x00, 0x0b); 885 if (ret) 886 return ret; 887 888 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 889 CXD2880_IO_TGT_DMD, 890 0x86, data, sizeof(data)); 891 if (ret) 892 return ret; 893 894 if (!(data[0] & 0x01)) 895 return -EAGAIN; 896 897 l1_post->sub_slices_per_frame = (data[1] & 0x7f) << 8; 898 l1_post->sub_slices_per_frame |= data[2]; 899 l1_post->num_plps = data[3]; 900 l1_post->num_aux = data[4] & 0x0f; 901 l1_post->aux_cfg_rfu = data[5]; 902 l1_post->rf_idx = data[6] & 0x07; 903 l1_post->freq = data[7] << 24; 904 l1_post->freq |= data[8] << 16; 905 l1_post->freq |= data[9] << 8; 906 l1_post->freq |= data[10]; 907 l1_post->fef_type = data[11] & 0x0f; 908 l1_post->fef_length = data[12] << 16; 909 l1_post->fef_length |= data[13] << 8; 910 l1_post->fef_length |= data[14]; 911 l1_post->fef_intvl = data[15]; 912 913 return 0; 914 } 915 916 int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd 917 *tnr_dmd, 918 enum cxd2880_dvbt2_plp_btype 919 type, 920 struct cxd2880_dvbt2_bbheader 921 *bbheader) 922 { 923 u8 sync_state = 0; 924 u8 ts_lock = 0; 925 u8 unlock_detected = 0; 926 u8 data[14]; 927 u8 addr = 0; 928 int ret; 929 930 if (!tnr_dmd || !bbheader) 931 return -EINVAL; 932 933 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 934 return -EINVAL; 935 936 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 937 return -EINVAL; 938 939 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 940 return -EINVAL; 941 942 ret = slvt_freeze_reg(tnr_dmd); 943 if (ret) 944 return ret; 945 946 ret = 947 cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, 948 &ts_lock, 949 &unlock_detected); 950 if (ret) { 951 slvt_unfreeze_reg(tnr_dmd); 952 return ret; 953 } 954 955 if (!ts_lock) { 956 slvt_unfreeze_reg(tnr_dmd); 957 return -EAGAIN; 958 } 959 960 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 961 CXD2880_IO_TGT_DMD, 962 0x00, 0x0b); 963 if (ret) { 964 slvt_unfreeze_reg(tnr_dmd); 965 return ret; 966 } 967 968 if (type == CXD2880_DVBT2_PLP_COMMON) { 969 u8 l1_post_ok; 970 u8 data; 971 972 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 973 CXD2880_IO_TGT_DMD, 974 0x86, &l1_post_ok, 1); 975 if (ret) { 976 slvt_unfreeze_reg(tnr_dmd); 977 return ret; 978 } 979 980 if (!(l1_post_ok & 0x01)) { 981 slvt_unfreeze_reg(tnr_dmd); 982 return -EAGAIN; 983 } 984 985 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 986 CXD2880_IO_TGT_DMD, 987 0xb6, &data, 1); 988 if (ret) { 989 slvt_unfreeze_reg(tnr_dmd); 990 return ret; 991 } 992 993 if (data == 0) { 994 slvt_unfreeze_reg(tnr_dmd); 995 return -EAGAIN; 996 } 997 } 998 999 if (type == CXD2880_DVBT2_PLP_COMMON) 1000 addr = 0x51; 1001 else 1002 addr = 0x42; 1003 1004 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 1005 CXD2880_IO_TGT_DMD, 1006 addr, data, sizeof(data)); 1007 if (ret) { 1008 slvt_unfreeze_reg(tnr_dmd); 1009 return ret; 1010 } 1011 1012 slvt_unfreeze_reg(tnr_dmd); 1013 1014 bbheader->stream_input = 1015 (enum cxd2880_dvbt2_stream)((data[0] >> 6) & 0x03); 1016 bbheader->is_single_input_stream = (data[0] >> 5) & 0x01; 1017 bbheader->is_constant_coding_modulation = 1018 (data[0] >> 4) & 0x01; 1019 bbheader->issy_indicator = (data[0] >> 3) & 0x01; 1020 bbheader->null_packet_deletion = (data[0] >> 2) & 0x01; 1021 bbheader->ext = data[0] & 0x03; 1022 1023 bbheader->input_stream_identifier = data[1]; 1024 bbheader->plp_mode = 1025 (data[3] & 0x01) ? CXD2880_DVBT2_PLP_MODE_HEM : 1026 CXD2880_DVBT2_PLP_MODE_NM; 1027 bbheader->data_field_length = (data[4] << 8) | data[5]; 1028 1029 if (bbheader->plp_mode == CXD2880_DVBT2_PLP_MODE_NM) { 1030 bbheader->user_packet_length = 1031 (data[6] << 8) | data[7]; 1032 bbheader->sync_byte = data[8]; 1033 bbheader->issy = 0; 1034 } else { 1035 bbheader->user_packet_length = 0; 1036 bbheader->sync_byte = 0; 1037 bbheader->issy = 1038 (data[11] << 16) | (data[12] << 8) | data[13]; 1039 } 1040 1041 return 0; 1042 } 1043 1044 int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd 1045 *tnr_dmd, 1046 enum 1047 cxd2880_dvbt2_plp_btype 1048 type, 1049 u32 *ts_rate_bps) 1050 { 1051 u8 sync_state = 0; 1052 u8 ts_lock = 0; 1053 u8 unlock_detected = 0; 1054 u8 l1_post_ok = 0; 1055 u8 data[4]; 1056 u8 addr = 0; 1057 1058 int ret; 1059 1060 if (!tnr_dmd || !ts_rate_bps) 1061 return -EINVAL; 1062 1063 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 1064 return -EINVAL; 1065 1066 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 1067 return -EINVAL; 1068 1069 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 1070 return -EINVAL; 1071 1072 ret = slvt_freeze_reg(tnr_dmd); 1073 if (ret) 1074 return ret; 1075 1076 ret = 1077 cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, 1078 &ts_lock, 1079 &unlock_detected); 1080 if (ret) { 1081 slvt_unfreeze_reg(tnr_dmd); 1082 return ret; 1083 } 1084 1085 if (!ts_lock) { 1086 slvt_unfreeze_reg(tnr_dmd); 1087 return -EAGAIN; 1088 } 1089 1090 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 1091 CXD2880_IO_TGT_DMD, 1092 0x00, 0x0b); 1093 if (ret) { 1094 slvt_unfreeze_reg(tnr_dmd); 1095 return ret; 1096 } 1097 1098 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 1099 CXD2880_IO_TGT_DMD, 1100 0x86, &l1_post_ok, 1); 1101 if (ret) { 1102 slvt_unfreeze_reg(tnr_dmd); 1103 return ret; 1104 } 1105 1106 if (!(l1_post_ok & 0x01)) { 1107 slvt_unfreeze_reg(tnr_dmd); 1108 return -EAGAIN; 1109 } 1110 1111 if (type == CXD2880_DVBT2_PLP_COMMON) 1112 addr = 0xba; 1113 else 1114 addr = 0xa7; 1115 1116 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 1117 CXD2880_IO_TGT_DMD, 1118 addr, &data[0], 1); 1119 if (ret) { 1120 slvt_unfreeze_reg(tnr_dmd); 1121 return ret; 1122 } 1123 1124 if ((data[0] & 0x80) == 0x00) { 1125 slvt_unfreeze_reg(tnr_dmd); 1126 return -EAGAIN; 1127 } 1128 1129 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 1130 CXD2880_IO_TGT_DMD, 1131 0x00, 0x25); 1132 if (ret) { 1133 slvt_unfreeze_reg(tnr_dmd); 1134 return ret; 1135 } 1136 1137 if (type == CXD2880_DVBT2_PLP_COMMON) 1138 addr = 0xa6; 1139 else 1140 addr = 0xaa; 1141 1142 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 1143 CXD2880_IO_TGT_DMD, 1144 addr, &data[0], 4); 1145 if (ret) { 1146 slvt_unfreeze_reg(tnr_dmd); 1147 return ret; 1148 } 1149 1150 *ts_rate_bps = ((data[0] & 0x07) << 24) | (data[1] << 16) | 1151 (data[2] << 8) | data[3]; 1152 1153 return 0; 1154 } 1155 1156 int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd 1157 *tnr_dmd, 1158 enum 1159 cxd2880_tnrdmd_spectrum_sense 1160 *sense) 1161 { 1162 u8 sync_state = 0; 1163 u8 ts_lock = 0; 1164 u8 early_unlock = 0; 1165 u8 data = 0; 1166 int ret; 1167 1168 if (!tnr_dmd || !sense) 1169 return -EINVAL; 1170 1171 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 1172 return -EINVAL; 1173 1174 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 1175 return -EINVAL; 1176 1177 ret = slvt_freeze_reg(tnr_dmd); 1178 if (ret) 1179 return ret; 1180 1181 ret = 1182 cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, &ts_lock, 1183 &early_unlock); 1184 if (ret) { 1185 slvt_unfreeze_reg(tnr_dmd); 1186 return ret; 1187 } 1188 1189 if (sync_state != 6) { 1190 slvt_unfreeze_reg(tnr_dmd); 1191 1192 ret = -EAGAIN; 1193 1194 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) 1195 ret = 1196 cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(tnr_dmd->diver_sub, 1197 sense); 1198 1199 return ret; 1200 } 1201 1202 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 1203 CXD2880_IO_TGT_DMD, 1204 0x00, 0x0b); 1205 if (ret) { 1206 slvt_unfreeze_reg(tnr_dmd); 1207 return ret; 1208 } 1209 1210 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 1211 CXD2880_IO_TGT_DMD, 1212 0x2f, &data, sizeof(data)); 1213 if (ret) { 1214 slvt_unfreeze_reg(tnr_dmd); 1215 return ret; 1216 } 1217 1218 slvt_unfreeze_reg(tnr_dmd); 1219 1220 *sense = 1221 (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV : 1222 CXD2880_TNRDMD_SPECTRUM_NORMAL; 1223 1224 return 0; 1225 } 1226 1227 static 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 1280 static 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 1298 int 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 1336 int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd 1337 *tnr_dmd, int *snr, 1338 int *snr_main, int *snr_sub) 1339 { 1340 u16 reg_value = 0; 1341 u32 reg_value_sum = 0; 1342 int ret; 1343 1344 if (!tnr_dmd || !snr || !snr_main || !snr_sub) 1345 return -EINVAL; 1346 1347 *snr = -1000 * 1000; 1348 *snr_main = -1000 * 1000; 1349 *snr_sub = -1000 * 1000; 1350 1351 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) 1352 return -EINVAL; 1353 1354 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 1355 return -EINVAL; 1356 1357 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 1358 return -EINVAL; 1359 1360 ret = dvbt2_read_snr_reg(tnr_dmd, ®_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 1389 int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct 1390 cxd2880_tnrdmd 1391 *tnr_dmd, 1392 u32 *pen) 1393 { 1394 int ret; 1395 u8 data[3]; 1396 1397 if (!tnr_dmd || !pen) 1398 return -EINVAL; 1399 1400 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 1401 return -EINVAL; 1402 1403 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 1404 return -EINVAL; 1405 1406 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 1407 return -EINVAL; 1408 1409 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 1410 CXD2880_IO_TGT_DMD, 1411 0x00, 0x0b); 1412 if (ret) 1413 return ret; 1414 1415 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 1416 CXD2880_IO_TGT_DMD, 1417 0x39, data, sizeof(data)); 1418 if (ret) 1419 return ret; 1420 1421 if (!(data[0] & 0x01)) 1422 return -EAGAIN; 1423 1424 *pen = ((data[1] << 8) | data[2]); 1425 1426 return ret; 1427 } 1428 1429 int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd 1430 *tnr_dmd, int *ppm) 1431 { 1432 u8 ctl_val_reg[5]; 1433 u8 nominal_rate_reg[5]; 1434 u32 trl_ctl_val = 0; 1435 u32 trcg_nominal_rate = 0; 1436 int num; 1437 int den; 1438 int ret; 1439 u8 sync_state = 0; 1440 u8 ts_lock = 0; 1441 u8 unlock_detected = 0; 1442 s8 diff_upper = 0; 1443 1444 if (!tnr_dmd || !ppm) 1445 return -EINVAL; 1446 1447 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 1448 return -EINVAL; 1449 1450 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 1451 return -EINVAL; 1452 1453 ret = slvt_freeze_reg(tnr_dmd); 1454 if (ret) 1455 return ret; 1456 1457 ret = 1458 cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, 1459 &ts_lock, 1460 &unlock_detected); 1461 if (ret) { 1462 slvt_unfreeze_reg(tnr_dmd); 1463 return ret; 1464 } 1465 1466 if (sync_state != 6) { 1467 slvt_unfreeze_reg(tnr_dmd); 1468 return -EAGAIN; 1469 } 1470 1471 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 1472 CXD2880_IO_TGT_DMD, 1473 0x00, 0x0b); 1474 if (ret) { 1475 slvt_unfreeze_reg(tnr_dmd); 1476 return ret; 1477 } 1478 1479 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 1480 CXD2880_IO_TGT_DMD, 1481 0x34, ctl_val_reg, 1482 sizeof(ctl_val_reg)); 1483 if (ret) { 1484 slvt_unfreeze_reg(tnr_dmd); 1485 return ret; 1486 } 1487 1488 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 1489 CXD2880_IO_TGT_DMD, 1490 0x00, 0x04); 1491 if (ret) { 1492 slvt_unfreeze_reg(tnr_dmd); 1493 return ret; 1494 } 1495 1496 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 1497 CXD2880_IO_TGT_DMD, 1498 0x10, nominal_rate_reg, 1499 sizeof(nominal_rate_reg)); 1500 if (ret) { 1501 slvt_unfreeze_reg(tnr_dmd); 1502 return ret; 1503 } 1504 1505 slvt_unfreeze_reg(tnr_dmd); 1506 1507 diff_upper = 1508 (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f); 1509 1510 if (diff_upper < -1 || diff_upper > 1) 1511 return -EAGAIN; 1512 1513 trl_ctl_val = ctl_val_reg[1] << 24; 1514 trl_ctl_val |= ctl_val_reg[2] << 16; 1515 trl_ctl_val |= ctl_val_reg[3] << 8; 1516 trl_ctl_val |= ctl_val_reg[4]; 1517 1518 trcg_nominal_rate = nominal_rate_reg[1] << 24; 1519 trcg_nominal_rate |= nominal_rate_reg[2] << 16; 1520 trcg_nominal_rate |= nominal_rate_reg[3] << 8; 1521 trcg_nominal_rate |= nominal_rate_reg[4]; 1522 1523 trl_ctl_val >>= 1; 1524 trcg_nominal_rate >>= 1; 1525 1526 if (diff_upper == 1) 1527 num = 1528 (int)((trl_ctl_val + 0x80000000u) - 1529 trcg_nominal_rate); 1530 else if (diff_upper == -1) 1531 num = 1532 -(int)((trcg_nominal_rate + 0x80000000u) - 1533 trl_ctl_val); 1534 else 1535 num = (int)(trl_ctl_val - trcg_nominal_rate); 1536 1537 den = (nominal_rate_reg[0] & 0x7f) << 24; 1538 den |= nominal_rate_reg[1] << 16; 1539 den |= nominal_rate_reg[2] << 8; 1540 den |= nominal_rate_reg[3]; 1541 den = (den + (390625 / 2)) / 390625; 1542 1543 den >>= 1; 1544 1545 if (num >= 0) 1546 *ppm = (num + (den / 2)) / den; 1547 else 1548 *ppm = (num - (den / 2)) / den; 1549 1550 return 0; 1551 } 1552 1553 int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct 1554 cxd2880_tnrdmd 1555 *tnr_dmd, 1556 int *ppm) 1557 { 1558 if (!tnr_dmd || !ppm) 1559 return -EINVAL; 1560 1561 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) 1562 return -EINVAL; 1563 1564 return cxd2880_tnrdmd_dvbt2_mon_sampling_offset(tnr_dmd->diver_sub, 1565 ppm); 1566 } 1567 1568 int 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 1651 int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd 1652 *tnr_dmd, 1653 enum cxd2880_dvbt2_plp_btype 1654 type, 1655 enum 1656 cxd2880_dvbt2_plp_code_rate 1657 *code_rate) 1658 { 1659 u8 data; 1660 u8 l1_post_ok = 0; 1661 int ret; 1662 1663 if (!tnr_dmd || !code_rate) 1664 return -EINVAL; 1665 1666 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 1667 return -EINVAL; 1668 1669 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 1670 return -EINVAL; 1671 1672 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 1673 return -EINVAL; 1674 1675 ret = slvt_freeze_reg(tnr_dmd); 1676 if (ret) 1677 return ret; 1678 1679 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 1680 CXD2880_IO_TGT_DMD, 1681 0x00, 0x0b); 1682 if (ret) { 1683 slvt_unfreeze_reg(tnr_dmd); 1684 return ret; 1685 } 1686 1687 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 1688 CXD2880_IO_TGT_DMD, 1689 0x86, &l1_post_ok, 1); 1690 if (ret) { 1691 slvt_unfreeze_reg(tnr_dmd); 1692 return ret; 1693 } 1694 1695 if (!(l1_post_ok & 0x01)) { 1696 slvt_unfreeze_reg(tnr_dmd); 1697 return -EAGAIN; 1698 } 1699 1700 if (type == CXD2880_DVBT2_PLP_COMMON) { 1701 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 1702 CXD2880_IO_TGT_DMD, 1703 0xb6, &data, 1); 1704 if (ret) { 1705 slvt_unfreeze_reg(tnr_dmd); 1706 return ret; 1707 } 1708 1709 if (data == 0) { 1710 slvt_unfreeze_reg(tnr_dmd); 1711 return -EAGAIN; 1712 } 1713 1714 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 1715 CXD2880_IO_TGT_DMD, 1716 0xb0, &data, 1); 1717 if (ret) { 1718 slvt_unfreeze_reg(tnr_dmd); 1719 return ret; 1720 } 1721 } else { 1722 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 1723 CXD2880_IO_TGT_DMD, 1724 0x9d, &data, 1); 1725 if (ret) { 1726 slvt_unfreeze_reg(tnr_dmd); 1727 return ret; 1728 } 1729 } 1730 1731 slvt_unfreeze_reg(tnr_dmd); 1732 1733 *code_rate = (enum cxd2880_dvbt2_plp_code_rate)(data & 0x07); 1734 1735 return ret; 1736 } 1737 1738 int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd 1739 *tnr_dmd, 1740 enum cxd2880_dvbt2_profile 1741 *profile) 1742 { 1743 u8 data; 1744 int ret; 1745 1746 if (!tnr_dmd || !profile) 1747 return -EINVAL; 1748 1749 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 1750 return -EINVAL; 1751 1752 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 1753 return -EINVAL; 1754 1755 ret = tnr_dmd->io->write_reg(tnr_dmd->io, 1756 CXD2880_IO_TGT_DMD, 1757 0x00, 0x0b); 1758 if (ret) 1759 return ret; 1760 1761 ret = tnr_dmd->io->read_regs(tnr_dmd->io, 1762 CXD2880_IO_TGT_DMD, 1763 0x22, &data, sizeof(data)); 1764 if (ret) 1765 return ret; 1766 1767 if (data & 0x02) { 1768 if (data & 0x01) 1769 *profile = CXD2880_DVBT2_PROFILE_LITE; 1770 else 1771 *profile = CXD2880_DVBT2_PROFILE_BASE; 1772 } else { 1773 ret = -EAGAIN; 1774 if (tnr_dmd->diver_mode == 1775 CXD2880_TNRDMD_DIVERMODE_MAIN) 1776 ret = 1777 cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd->diver_sub, 1778 profile); 1779 1780 return ret; 1781 } 1782 1783 return 0; 1784 } 1785 1786 static int dvbt2_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd, 1787 int rf_lvl, u8 *ssi) 1788 { 1789 enum cxd2880_dvbt2_plp_constell qam; 1790 enum cxd2880_dvbt2_plp_code_rate code_rate; 1791 int prel; 1792 int temp_ssi = 0; 1793 int ret; 1794 1795 if (!tnr_dmd || !ssi) 1796 return -EINVAL; 1797 1798 ret = 1799 cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam); 1800 if (ret) 1801 return ret; 1802 1803 ret = 1804 cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA, 1805 &code_rate); 1806 if (ret) 1807 return ret; 1808 1809 if (code_rate > CXD2880_DVBT2_R2_5 || qam > CXD2880_DVBT2_QAM256) 1810 return -EINVAL; 1811 1812 prel = rf_lvl - ref_dbm_1000[qam][code_rate]; 1813 1814 if (prel < -15000) 1815 temp_ssi = 0; 1816 else if (prel < 0) 1817 temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000; 1818 else if (prel < 20000) 1819 temp_ssi = (((4 * prel) + 500) / 1000) + 10; 1820 else if (prel < 35000) 1821 temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90; 1822 else 1823 temp_ssi = 100; 1824 1825 *ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi; 1826 1827 return ret; 1828 } 1829 1830 int 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 1855 int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd 1856 *tnr_dmd, u8 *ssi) 1857 { 1858 int rf_lvl = 0; 1859 int ret; 1860 1861 if (!tnr_dmd || !ssi) 1862 return -EINVAL; 1863 1864 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) 1865 return -EINVAL; 1866 1867 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 1868 return -EINVAL; 1869 1870 if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) 1871 return -EINVAL; 1872 1873 ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl); 1874 if (ret) 1875 return ret; 1876 1877 return dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi); 1878 } 1879