brintos

brintos / linux-shallow public Read only

0
0
Text · 38.7 KiB · 4e173dd Raw
1879 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * cxd2880_tnrdmd_dvbt2_mon.c4 * Sony CXD2880 DVB-T2/T tuner + demodulator driver5 * DVB-T2 monitor functions6 *7 * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation8 */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_tnrdmd24				       *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_tnrdmd63					   *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_tnrdmd82					    *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(struct159						cxd2880_tnrdmd160						*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_l1pre175				    *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_sub215			    (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_tnrdmd351				     *tnr_dmd,352				     enum cxd2880_dvbt2_version353				     *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_sub392			    (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_tnrdmd509				       *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_tnrdmd604					*tnr_dmd,605					enum606					cxd2880_dvbt2_plp_btype607					type,608					struct cxd2880_dvbt2_plp609					*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	else657		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_tnrdmd710					    *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_tnrdmd769				       *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_sub807			    (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_tnrdmd863				     *tnr_dmd,864				     struct cxd2880_dvbt2_l1post865				     *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_tnrdmd917				      *tnr_dmd,918				      enum cxd2880_dvbt2_plp_btype919				      type,920				      struct cxd2880_dvbt2_bbheader921				      *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	else1002		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_tnrdmd1045					      *tnr_dmd,1046					      enum1047					      cxd2880_dvbt2_plp_btype1048					      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	else1114		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	else1140		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_tnrdmd1157					    *tnr_dmd,1158					    enum1159					    cxd2880_tnrdmd_spectrum_sense1160					    *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_tnrdmd1337				       *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(struct1390						 cxd2880_tnrdmd1391						 *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_tnrdmd1430					     *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	else1535		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	else1548		*ppm = (num - (den / 2)) / den;1549 1550	return 0;1551}1552 1553int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct1554						 cxd2880_tnrdmd1555						 *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_tnrdmd1652				       *tnr_dmd,1653				       enum cxd2880_dvbt2_plp_btype1654				       type,1655				       enum1656				       cxd2880_dvbt2_plp_code_rate1657				       *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_tnrdmd1739				     *tnr_dmd,1740				     enum cxd2880_dvbt2_profile1741				     *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		else1771			*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	else1823		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_tnrdmd1856				     *tnr_dmd, u8 *ssi)1857{1858	int rf_lvl = 0;1859	int ret;1860 1861	if (!tnr_dmd || !ssi)1862		return -EINVAL;1863 1864	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)1865		return -EINVAL;1866 1867	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)1868		return -EINVAL;1869 1870	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)1871		return -EINVAL;1872 1873	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);1874	if (ret)1875		return ret;1876 1877	return dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);1878}1879