cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cxd2880_tnrdmd_dvbt2_mon.c (39660B)


      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
     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}