File Index
Files and directories
Sign in
FILE

cxd2880_tnrdmd_dvbt2_mon.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c C
   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 <linux/int_log.h>
  15
  16static const int ref_dbm_1000[4][8] = {
  17	{-96000, -95000, -94000, -93000, -92000, -92000, -98000, -97000},
  18	{-91000, -89000, -88000, -87000, -86000, -86000, -93000, -92000},
  19	{-86000, -85000, -83000, -82000, -81000, -80000, -89000, -88000},
  20	{-82000, -80000, -78000, -76000, -75000, -74000, -86000, -84000},
  21};
  22
  23int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_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
  62int 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
  81int 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
 158int 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
 173int 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
 350int 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
 433int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
 434				  struct cxd2880_dvbt2_ofdm *ofdm)
 435{
 436	u8 data[5];
 437	u8 sync_state = 0;
 438	u8 ts_lock = 0;
 439	u8 unlock_detected = 0;
 440	int ret;
 441
 442	if (!tnr_dmd || !ofdm)
 443		return -EINVAL;
 444
 445	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
 446		return -EINVAL;
 447
 448	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
 449		return -EINVAL;
 450
 451	ret = slvt_freeze_reg(tnr_dmd);
 452	if (ret)
 453		return ret;
 454
 455	ret =
 456	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
 457					       &ts_lock,
 458					       &unlock_detected);
 459	if (ret) {
 460		slvt_unfreeze_reg(tnr_dmd);
 461		return ret;
 462	}
 463
 464	if (sync_state != 6) {
 465		slvt_unfreeze_reg(tnr_dmd);
 466
 467		ret = -EAGAIN;
 468
 469		if (tnr_dmd->diver_mode ==
 470		    CXD2880_TNRDMD_DIVERMODE_MAIN)
 471			ret =
 472			    cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd->diver_sub,
 473							  ofdm);
 474
 475		return ret;
 476	}
 477
 478	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
 479				     CXD2880_IO_TGT_DMD,
 480				     0x00, 0x0b);
 481	if (ret) {
 482		slvt_unfreeze_reg(tnr_dmd);
 483		return ret;
 484	}
 485
 486	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
 487				     CXD2880_IO_TGT_DMD,
 488				     0x1d, data, sizeof(data));
 489	if (ret) {
 490		slvt_unfreeze_reg(tnr_dmd);
 491		return ret;
 492	}
 493
 494	slvt_unfreeze_reg(tnr_dmd);
 495
 496	ofdm->mixed = ((data[0] & 0x20) ? 1 : 0);
 497	ofdm->is_miso = ((data[0] & 0x10) >> 4);
 498	ofdm->mode = (enum cxd2880_dvbt2_mode)(data[0] & 0x07);
 499	ofdm->gi = (enum cxd2880_dvbt2_guard)((data[1] & 0x70) >> 4);
 500	ofdm->pp = (enum cxd2880_dvbt2_pp)(data[1] & 0x07);
 501	ofdm->bw_ext = (data[2] & 0x10) >> 4;
 502	ofdm->papr = (enum cxd2880_dvbt2_papr)(data[2] & 0x0f);
 503	ofdm->num_symbols = (data[3] << 8) | data[4];
 504
 505	return 0;
 506}
 507
 508int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_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
 603int 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
 709int 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
 768int 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
 862int 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
 916int 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
1044int 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
1156int 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
1227static int dvbt2_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
1228			      u16 *reg_value)
1229{
1230	u8 sync_state = 0;
1231	u8 ts_lock = 0;
1232	u8 unlock_detected = 0;
1233	u8 data[2];
1234	int ret;
1235
1236	if (!tnr_dmd || !reg_value)
1237		return -EINVAL;
1238
1239	ret = slvt_freeze_reg(tnr_dmd);
1240	if (ret)
1241		return ret;
1242
1243	ret =
1244	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
1245					       &ts_lock,
1246					       &unlock_detected);
1247	if (ret) {
1248		slvt_unfreeze_reg(tnr_dmd);
1249		return ret;
1250	}
1251
1252	if (sync_state != 6) {
1253		slvt_unfreeze_reg(tnr_dmd);
1254		return -EAGAIN;
1255	}
1256
1257	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1258				     CXD2880_IO_TGT_DMD,
1259				     0x00, 0x0b);
1260	if (ret) {
1261		slvt_unfreeze_reg(tnr_dmd);
1262		return ret;
1263	}
1264
1265	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1266				     CXD2880_IO_TGT_DMD,
1267				     0x13, data, sizeof(data));
1268	if (ret) {
1269		slvt_unfreeze_reg(tnr_dmd);
1270		return ret;
1271	}
1272
1273	slvt_unfreeze_reg(tnr_dmd);
1274
1275	*reg_value = (data[0] << 8) | data[1];
1276
1277	return ret;
1278}
1279
1280static int dvbt2_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
1281			  u32 reg_value, int *snr)
1282{
1283	if (!tnr_dmd || !snr)
1284		return -EINVAL;
1285
1286	if (reg_value == 0)
1287		return -EAGAIN;
1288
1289	if (reg_value > 10876)
1290		reg_value = 10876;
1291
1292	*snr = intlog10(reg_value) - intlog10(12600 - reg_value);
1293	*snr = (*snr + 839) / 1678 + 32000;
1294
1295	return 0;
1296}
1297
1298int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
1299				 int *snr)
1300{
1301	u16 reg_value = 0;
1302	int ret;
1303
1304	if (!tnr_dmd || !snr)
1305		return -EINVAL;
1306
1307	*snr = -1000 * 1000;
1308
1309	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1310		return -EINVAL;
1311
1312	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1313		return -EINVAL;
1314
1315	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1316		return -EINVAL;
1317
1318	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
1319		ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
1320		if (ret)
1321			return ret;
1322
1323		ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr);
1324	} else {
1325		int snr_main = 0;
1326		int snr_sub = 0;
1327
1328		ret =
1329		    cxd2880_tnrdmd_dvbt2_mon_snr_diver(tnr_dmd, snr, &snr_main,
1330						       &snr_sub);
1331	}
1332
1333	return ret;
1334}
1335
1336int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_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, &reg_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, &reg_value);
1374	if (!ret) {
1375		ret = dvbt2_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
1376		if (ret)
1377			reg_value = 0;
1378	} else if (ret == -EAGAIN) {
1379		reg_value = 0;
1380	} else {
1381		return ret;
1382	}
1383
1384	reg_value_sum += reg_value;
1385
1386	return dvbt2_calc_snr(tnr_dmd, reg_value_sum, snr);
1387}
1388
1389int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(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
1429int 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
1553int 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
1568int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
1569				 enum cxd2880_dvbt2_plp_btype type,
1570				 enum cxd2880_dvbt2_plp_constell *qam)
1571{
1572	u8 data;
1573	u8 l1_post_ok = 0;
1574	int ret;
1575
1576	if (!tnr_dmd || !qam)
1577		return -EINVAL;
1578
1579	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1580		return -EINVAL;
1581
1582	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1583		return -EINVAL;
1584
1585	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1586		return -EINVAL;
1587
1588	ret = slvt_freeze_reg(tnr_dmd);
1589	if (ret)
1590		return ret;
1591
1592	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1593				     CXD2880_IO_TGT_DMD,
1594				     0x00, 0x0b);
1595	if (ret) {
1596		slvt_unfreeze_reg(tnr_dmd);
1597		return ret;
1598	}
1599
1600	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1601				     CXD2880_IO_TGT_DMD,
1602				     0x86, &l1_post_ok, 1);
1603	if (ret) {
1604		slvt_unfreeze_reg(tnr_dmd);
1605		return ret;
1606	}
1607
1608	if (!(l1_post_ok & 0x01)) {
1609		slvt_unfreeze_reg(tnr_dmd);
1610		return -EAGAIN;
1611	}
1612
1613	if (type == CXD2880_DVBT2_PLP_COMMON) {
1614		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1615					     CXD2880_IO_TGT_DMD,
1616					     0xb6, &data, 1);
1617		if (ret) {
1618			slvt_unfreeze_reg(tnr_dmd);
1619			return ret;
1620		}
1621
1622		if (data == 0) {
1623			slvt_unfreeze_reg(tnr_dmd);
1624			return -EAGAIN;
1625		}
1626
1627		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1628					     CXD2880_IO_TGT_DMD,
1629					     0xb1, &data, 1);
1630		if (ret) {
1631			slvt_unfreeze_reg(tnr_dmd);
1632			return ret;
1633		}
1634	} else {
1635		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1636					     CXD2880_IO_TGT_DMD,
1637					     0x9e, &data, 1);
1638		if (ret) {
1639			slvt_unfreeze_reg(tnr_dmd);
1640			return ret;
1641		}
1642	}
1643
1644	slvt_unfreeze_reg(tnr_dmd);
1645
1646	*qam = (enum cxd2880_dvbt2_plp_constell)(data & 0x07);
1647
1648	return ret;
1649}
1650
1651int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_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
1738int 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
1786static int dvbt2_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
1787			  int rf_lvl, u8 *ssi)
1788{
1789	enum cxd2880_dvbt2_plp_constell qam;
1790	enum cxd2880_dvbt2_plp_code_rate code_rate;
1791	int prel;
1792	int temp_ssi = 0;
1793	int ret;
1794
1795	if (!tnr_dmd || !ssi)
1796		return -EINVAL;
1797
1798	ret =
1799	    cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam);
1800	if (ret)
1801		return ret;
1802
1803	ret =
1804	    cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA,
1805					       &code_rate);
1806	if (ret)
1807		return ret;
1808
1809	if (code_rate > CXD2880_DVBT2_R2_5 || qam > CXD2880_DVBT2_QAM256)
1810		return -EINVAL;
1811
1812	prel = rf_lvl - ref_dbm_1000[qam][code_rate];
1813
1814	if (prel < -15000)
1815		temp_ssi = 0;
1816	else if (prel < 0)
1817		temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
1818	else if (prel < 20000)
1819		temp_ssi = (((4 * prel) + 500) / 1000) + 10;
1820	else if (prel < 35000)
1821		temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
1822	else
1823		temp_ssi = 100;
1824
1825	*ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
1826
1827	return ret;
1828}
1829
1830int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
1831				 u8 *ssi)
1832{
1833	int rf_lvl = 0;
1834	int ret;
1835
1836	if (!tnr_dmd || !ssi)
1837		return -EINVAL;
1838
1839	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1840		return -EINVAL;
1841
1842	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1843		return -EINVAL;
1844
1845	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1846		return -EINVAL;
1847
1848	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
1849	if (ret)
1850		return ret;
1851
1852	return dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);
1853}
1854
1855int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_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}
~/ Read-only file preview.