162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * cxd2880_top.c 462306a36Sopenharmony_ci * Sony CXD2880 DVB-T2/T tuner + demodulator driver 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/spi/spi.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <media/dvb_frontend.h> 1462306a36Sopenharmony_ci#include <linux/int_log.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "cxd2880.h" 1762306a36Sopenharmony_ci#include "cxd2880_tnrdmd_mon.h" 1862306a36Sopenharmony_ci#include "cxd2880_tnrdmd_dvbt2_mon.h" 1962306a36Sopenharmony_ci#include "cxd2880_tnrdmd_dvbt_mon.h" 2062306a36Sopenharmony_ci#include "cxd2880_integ.h" 2162306a36Sopenharmony_ci#include "cxd2880_tnrdmd_dvbt2.h" 2262306a36Sopenharmony_ci#include "cxd2880_tnrdmd_dvbt.h" 2362306a36Sopenharmony_ci#include "cxd2880_devio_spi.h" 2462306a36Sopenharmony_ci#include "cxd2880_spi_device.h" 2562306a36Sopenharmony_ci#include "cxd2880_tnrdmd_driver_version.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistruct cxd2880_priv { 2862306a36Sopenharmony_ci struct cxd2880_tnrdmd tnrdmd; 2962306a36Sopenharmony_ci struct spi_device *spi; 3062306a36Sopenharmony_ci struct cxd2880_io regio; 3162306a36Sopenharmony_ci struct cxd2880_spi_device spi_device; 3262306a36Sopenharmony_ci struct cxd2880_spi cxd2880_spi; 3362306a36Sopenharmony_ci struct cxd2880_dvbt_tune_param dvbt_tune_param; 3462306a36Sopenharmony_ci struct cxd2880_dvbt2_tune_param dvbt2_tune_param; 3562306a36Sopenharmony_ci struct mutex *spi_mutex; /* For SPI access exclusive control */ 3662306a36Sopenharmony_ci unsigned long pre_ber_update; 3762306a36Sopenharmony_ci unsigned long pre_ber_interval; 3862306a36Sopenharmony_ci unsigned long post_ber_update; 3962306a36Sopenharmony_ci unsigned long post_ber_interval; 4062306a36Sopenharmony_ci unsigned long ucblock_update; 4162306a36Sopenharmony_ci unsigned long ucblock_interval; 4262306a36Sopenharmony_ci enum fe_status s; 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic int cxd2880_pre_bit_err_t(struct cxd2880_tnrdmd *tnrdmd, 4662306a36Sopenharmony_ci u32 *pre_bit_err, u32 *pre_bit_count) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci u8 rdata[2]; 4962306a36Sopenharmony_ci int ret; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (!tnrdmd || !pre_bit_err || !pre_bit_count) 5262306a36Sopenharmony_ci return -EINVAL; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 5562306a36Sopenharmony_ci return -EINVAL; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 5862306a36Sopenharmony_ci return -EINVAL; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) 6162306a36Sopenharmony_ci return -EINVAL; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci ret = slvt_freeze_reg(tnrdmd); 6462306a36Sopenharmony_ci if (ret) 6562306a36Sopenharmony_ci return ret; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci ret = tnrdmd->io->write_reg(tnrdmd->io, 6862306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 6962306a36Sopenharmony_ci 0x00, 0x10); 7062306a36Sopenharmony_ci if (ret) { 7162306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 7262306a36Sopenharmony_ci return ret; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 7662306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 7762306a36Sopenharmony_ci 0x39, rdata, 1); 7862306a36Sopenharmony_ci if (ret) { 7962306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 8062306a36Sopenharmony_ci return ret; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if ((rdata[0] & 0x01) == 0) { 8462306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 8562306a36Sopenharmony_ci return -EAGAIN; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 8962306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 9062306a36Sopenharmony_ci 0x22, rdata, 2); 9162306a36Sopenharmony_ci if (ret) { 9262306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 9362306a36Sopenharmony_ci return ret; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci *pre_bit_err = (rdata[0] << 8) | rdata[1]; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 9962306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 10062306a36Sopenharmony_ci 0x6f, rdata, 1); 10162306a36Sopenharmony_ci if (ret) { 10262306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 10362306a36Sopenharmony_ci return ret; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci *pre_bit_count = ((rdata[0] & 0x07) == 0) ? 10962306a36Sopenharmony_ci 256 : (0x1000 << (rdata[0] & 0x07)); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int cxd2880_pre_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd, 11562306a36Sopenharmony_ci u32 *pre_bit_err, 11662306a36Sopenharmony_ci u32 *pre_bit_count) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci u32 period_exp = 0; 11962306a36Sopenharmony_ci u32 n_ldpc = 0; 12062306a36Sopenharmony_ci u8 data[5]; 12162306a36Sopenharmony_ci int ret; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (!tnrdmd || !pre_bit_err || !pre_bit_count) 12462306a36Sopenharmony_ci return -EINVAL; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 12762306a36Sopenharmony_ci return -EINVAL; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 13062306a36Sopenharmony_ci return -EINVAL; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) 13362306a36Sopenharmony_ci return -EINVAL; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci ret = slvt_freeze_reg(tnrdmd); 13662306a36Sopenharmony_ci if (ret) 13762306a36Sopenharmony_ci return ret; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci ret = tnrdmd->io->write_reg(tnrdmd->io, 14062306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 14162306a36Sopenharmony_ci 0x00, 0x0b); 14262306a36Sopenharmony_ci if (ret) { 14362306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 14462306a36Sopenharmony_ci return ret; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 14862306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 14962306a36Sopenharmony_ci 0x3c, data, sizeof(data)); 15062306a36Sopenharmony_ci if (ret) { 15162306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 15262306a36Sopenharmony_ci return ret; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (!(data[0] & 0x01)) { 15662306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 15762306a36Sopenharmony_ci return -EAGAIN; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci *pre_bit_err = 16062306a36Sopenharmony_ci ((data[1] & 0x0f) << 24) | (data[2] << 16) | (data[3] << 8) | data[4]; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 16362306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 16462306a36Sopenharmony_ci 0xa0, data, 1); 16562306a36Sopenharmony_ci if (ret) { 16662306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 16762306a36Sopenharmony_ci return ret; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) == 17162306a36Sopenharmony_ci CXD2880_DVBT2_FEC_LDPC_16K) 17262306a36Sopenharmony_ci n_ldpc = 16200; 17362306a36Sopenharmony_ci else 17462306a36Sopenharmony_ci n_ldpc = 64800; 17562306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci ret = tnrdmd->io->write_reg(tnrdmd->io, 17862306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 17962306a36Sopenharmony_ci 0x00, 0x20); 18062306a36Sopenharmony_ci if (ret) 18162306a36Sopenharmony_ci return ret; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 18462306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 18562306a36Sopenharmony_ci 0x6f, data, 1); 18662306a36Sopenharmony_ci if (ret) 18762306a36Sopenharmony_ci return ret; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci period_exp = data[0] & 0x0f; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci *pre_bit_count = (1U << period_exp) * n_ldpc; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic int cxd2880_post_bit_err_t(struct cxd2880_tnrdmd *tnrdmd, 19762306a36Sopenharmony_ci u32 *post_bit_err, 19862306a36Sopenharmony_ci u32 *post_bit_count) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci u8 rdata[3]; 20162306a36Sopenharmony_ci u32 bit_error = 0; 20262306a36Sopenharmony_ci u32 period_exp = 0; 20362306a36Sopenharmony_ci int ret; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (!tnrdmd || !post_bit_err || !post_bit_count) 20662306a36Sopenharmony_ci return -EINVAL; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 20962306a36Sopenharmony_ci return -EINVAL; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 21262306a36Sopenharmony_ci return -EINVAL; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) 21562306a36Sopenharmony_ci return -EINVAL; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci ret = tnrdmd->io->write_reg(tnrdmd->io, 21862306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 21962306a36Sopenharmony_ci 0x00, 0x0d); 22062306a36Sopenharmony_ci if (ret) 22162306a36Sopenharmony_ci return ret; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 22462306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 22562306a36Sopenharmony_ci 0x15, rdata, 3); 22662306a36Sopenharmony_ci if (ret) 22762306a36Sopenharmony_ci return ret; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if ((rdata[0] & 0x40) == 0) 23062306a36Sopenharmony_ci return -EAGAIN; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci *post_bit_err = ((rdata[0] & 0x3f) << 16) | (rdata[1] << 8) | rdata[2]; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci ret = tnrdmd->io->write_reg(tnrdmd->io, 23562306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 23662306a36Sopenharmony_ci 0x00, 0x10); 23762306a36Sopenharmony_ci if (ret) 23862306a36Sopenharmony_ci return ret; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 24162306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 24262306a36Sopenharmony_ci 0x60, rdata, 1); 24362306a36Sopenharmony_ci if (ret) 24462306a36Sopenharmony_ci return ret; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci period_exp = (rdata[0] & 0x1f); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (period_exp <= 11 && (bit_error > (1U << period_exp) * 204 * 8)) 24962306a36Sopenharmony_ci return -EAGAIN; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci *post_bit_count = (1U << period_exp) * 204 * 8; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci return 0; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic int cxd2880_post_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd, 25762306a36Sopenharmony_ci u32 *post_bit_err, 25862306a36Sopenharmony_ci u32 *post_bit_count) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci u32 period_exp = 0; 26162306a36Sopenharmony_ci u32 n_bch = 0; 26262306a36Sopenharmony_ci u8 data[3]; 26362306a36Sopenharmony_ci enum cxd2880_dvbt2_plp_fec plp_fec_type = 26462306a36Sopenharmony_ci CXD2880_DVBT2_FEC_LDPC_16K; 26562306a36Sopenharmony_ci enum cxd2880_dvbt2_plp_code_rate plp_code_rate = 26662306a36Sopenharmony_ci CXD2880_DVBT2_R1_2; 26762306a36Sopenharmony_ci int ret; 26862306a36Sopenharmony_ci static const u16 n_bch_bits_lookup[2][8] = { 26962306a36Sopenharmony_ci {7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480}, 27062306a36Sopenharmony_ci {32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920} 27162306a36Sopenharmony_ci }; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (!tnrdmd || !post_bit_err || !post_bit_count) 27462306a36Sopenharmony_ci return -EINVAL; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 27762306a36Sopenharmony_ci return -EINVAL; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 28062306a36Sopenharmony_ci return -EINVAL; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) 28362306a36Sopenharmony_ci return -EINVAL; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci ret = slvt_freeze_reg(tnrdmd); 28662306a36Sopenharmony_ci if (ret) 28762306a36Sopenharmony_ci return ret; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci ret = tnrdmd->io->write_reg(tnrdmd->io, 29062306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 29162306a36Sopenharmony_ci 0x00, 0x0b); 29262306a36Sopenharmony_ci if (ret) { 29362306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 29462306a36Sopenharmony_ci return ret; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 29862306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 29962306a36Sopenharmony_ci 0x15, data, 3); 30062306a36Sopenharmony_ci if (ret) { 30162306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 30262306a36Sopenharmony_ci return ret; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (!(data[0] & 0x40)) { 30662306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 30762306a36Sopenharmony_ci return -EAGAIN; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci *post_bit_err = 31162306a36Sopenharmony_ci ((data[0] & 0x3f) << 16) | (data[1] << 8) | data[2]; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 31462306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 31562306a36Sopenharmony_ci 0x9d, data, 1); 31662306a36Sopenharmony_ci if (ret) { 31762306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 31862306a36Sopenharmony_ci return ret; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci plp_code_rate = 32262306a36Sopenharmony_ci (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 32562306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 32662306a36Sopenharmony_ci 0xa0, data, 1); 32762306a36Sopenharmony_ci if (ret) { 32862306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 32962306a36Sopenharmony_ci return ret; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci slvt_unfreeze_reg(tnrdmd); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci ret = tnrdmd->io->write_reg(tnrdmd->io, 33762306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 33862306a36Sopenharmony_ci 0x00, 0x20); 33962306a36Sopenharmony_ci if (ret) 34062306a36Sopenharmony_ci return ret; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 34362306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 34462306a36Sopenharmony_ci 0x72, data, 1); 34562306a36Sopenharmony_ci if (ret) 34662306a36Sopenharmony_ci return ret; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci period_exp = data[0] & 0x0f; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K || 35162306a36Sopenharmony_ci plp_code_rate > CXD2880_DVBT2_R2_5) 35262306a36Sopenharmony_ci return -EAGAIN; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci n_bch = n_bch_bits_lookup[plp_fec_type][plp_code_rate]; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (*post_bit_err > ((1U << period_exp) * n_bch)) 35762306a36Sopenharmony_ci return -EAGAIN; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci *post_bit_count = (1U << period_exp) * n_bch; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci return 0; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic int cxd2880_read_block_err_t(struct cxd2880_tnrdmd *tnrdmd, 36562306a36Sopenharmony_ci u32 *block_err, 36662306a36Sopenharmony_ci u32 *block_count) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci u8 rdata[3]; 36962306a36Sopenharmony_ci int ret; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (!tnrdmd || !block_err || !block_count) 37262306a36Sopenharmony_ci return -EINVAL; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 37562306a36Sopenharmony_ci return -EINVAL; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 37862306a36Sopenharmony_ci return -EINVAL; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) 38162306a36Sopenharmony_ci return -EINVAL; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci ret = tnrdmd->io->write_reg(tnrdmd->io, 38462306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 38562306a36Sopenharmony_ci 0x00, 0x0d); 38662306a36Sopenharmony_ci if (ret) 38762306a36Sopenharmony_ci return ret; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 39062306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 39162306a36Sopenharmony_ci 0x18, rdata, 3); 39262306a36Sopenharmony_ci if (ret) 39362306a36Sopenharmony_ci return ret; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if ((rdata[0] & 0x01) == 0) 39662306a36Sopenharmony_ci return -EAGAIN; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci *block_err = (rdata[1] << 8) | rdata[2]; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci ret = tnrdmd->io->write_reg(tnrdmd->io, 40162306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 40262306a36Sopenharmony_ci 0x00, 0x10); 40362306a36Sopenharmony_ci if (ret) 40462306a36Sopenharmony_ci return ret; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 40762306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 40862306a36Sopenharmony_ci 0x5c, rdata, 1); 40962306a36Sopenharmony_ci if (ret) 41062306a36Sopenharmony_ci return ret; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci *block_count = 1U << (rdata[0] & 0x0f); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if ((*block_count == 0) || (*block_err > *block_count)) 41562306a36Sopenharmony_ci return -EAGAIN; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci return 0; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic int cxd2880_read_block_err_t2(struct cxd2880_tnrdmd *tnrdmd, 42162306a36Sopenharmony_ci u32 *block_err, 42262306a36Sopenharmony_ci u32 *block_count) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci u8 rdata[3]; 42562306a36Sopenharmony_ci int ret; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (!tnrdmd || !block_err || !block_count) 42862306a36Sopenharmony_ci return -EINVAL; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 43162306a36Sopenharmony_ci return -EINVAL; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 43462306a36Sopenharmony_ci return -EINVAL; 43562306a36Sopenharmony_ci if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) 43662306a36Sopenharmony_ci return -EINVAL; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci ret = tnrdmd->io->write_reg(tnrdmd->io, 43962306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 44062306a36Sopenharmony_ci 0x00, 0x0b); 44162306a36Sopenharmony_ci if (ret) 44262306a36Sopenharmony_ci return ret; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 44562306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 44662306a36Sopenharmony_ci 0x18, rdata, 3); 44762306a36Sopenharmony_ci if (ret) 44862306a36Sopenharmony_ci return ret; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if ((rdata[0] & 0x01) == 0) 45162306a36Sopenharmony_ci return -EAGAIN; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci *block_err = (rdata[1] << 8) | rdata[2]; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci ret = tnrdmd->io->write_reg(tnrdmd->io, 45662306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 45762306a36Sopenharmony_ci 0x00, 0x24); 45862306a36Sopenharmony_ci if (ret) 45962306a36Sopenharmony_ci return ret; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 46262306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 46362306a36Sopenharmony_ci 0xdc, rdata, 1); 46462306a36Sopenharmony_ci if (ret) 46562306a36Sopenharmony_ci return ret; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci *block_count = 1U << (rdata[0] & 0x0f); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if ((*block_count == 0) || (*block_err > *block_count)) 47062306a36Sopenharmony_ci return -EAGAIN; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic void cxd2880_release(struct dvb_frontend *fe) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct cxd2880_priv *priv = NULL; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (!fe) { 48062306a36Sopenharmony_ci pr_err("invalid arg.\n"); 48162306a36Sopenharmony_ci return; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci priv = fe->demodulator_priv; 48462306a36Sopenharmony_ci kfree(priv); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic int cxd2880_init(struct dvb_frontend *fe) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci int ret; 49062306a36Sopenharmony_ci struct cxd2880_priv *priv = NULL; 49162306a36Sopenharmony_ci struct cxd2880_tnrdmd_create_param create_param; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (!fe) { 49462306a36Sopenharmony_ci pr_err("invalid arg.\n"); 49562306a36Sopenharmony_ci return -EINVAL; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci priv = fe->demodulator_priv; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci create_param.ts_output_if = CXD2880_TNRDMD_TSOUT_IF_SPI; 50162306a36Sopenharmony_ci create_param.xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_NONE; 50262306a36Sopenharmony_ci create_param.en_internal_ldo = 1; 50362306a36Sopenharmony_ci create_param.xosc_cap = 18; 50462306a36Sopenharmony_ci create_param.xosc_i = 8; 50562306a36Sopenharmony_ci create_param.stationary_use = 1; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 50862306a36Sopenharmony_ci if (priv->tnrdmd.io != &priv->regio) { 50962306a36Sopenharmony_ci ret = cxd2880_tnrdmd_create(&priv->tnrdmd, 51062306a36Sopenharmony_ci &priv->regio, &create_param); 51162306a36Sopenharmony_ci if (ret) { 51262306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 51362306a36Sopenharmony_ci pr_info("cxd2880 tnrdmd create failed %d\n", ret); 51462306a36Sopenharmony_ci return ret; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci ret = cxd2880_integ_init(&priv->tnrdmd); 51862306a36Sopenharmony_ci if (ret) { 51962306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 52062306a36Sopenharmony_ci pr_err("cxd2880 integ init failed %d\n", ret); 52162306a36Sopenharmony_ci return ret; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci ret = cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, 52562306a36Sopenharmony_ci CXD2880_TNRDMD_CFG_TSPIN_CURRENT, 52662306a36Sopenharmony_ci 0x00); 52762306a36Sopenharmony_ci if (ret) { 52862306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 52962306a36Sopenharmony_ci pr_err("cxd2880 set config failed %d\n", ret); 53062306a36Sopenharmony_ci return ret; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci pr_debug("OK.\n"); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return ret; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic int cxd2880_sleep(struct dvb_frontend *fe) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci int ret; 54262306a36Sopenharmony_ci struct cxd2880_priv *priv = NULL; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (!fe) { 54562306a36Sopenharmony_ci pr_err("invalid arg\n"); 54662306a36Sopenharmony_ci return -EINVAL; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci priv = fe->demodulator_priv; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 55262306a36Sopenharmony_ci ret = cxd2880_tnrdmd_sleep(&priv->tnrdmd); 55362306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci pr_debug("tnrdmd_sleep ret %d\n", ret); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci return ret; 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cistatic int cxd2880_read_signal_strength(struct dvb_frontend *fe, 56162306a36Sopenharmony_ci u16 *strength) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci int ret; 56462306a36Sopenharmony_ci struct cxd2880_priv *priv = NULL; 56562306a36Sopenharmony_ci struct dtv_frontend_properties *c = NULL; 56662306a36Sopenharmony_ci int level = 0; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (!fe || !strength) { 56962306a36Sopenharmony_ci pr_err("invalid arg\n"); 57062306a36Sopenharmony_ci return -EINVAL; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci priv = fe->demodulator_priv; 57462306a36Sopenharmony_ci c = &fe->dtv_property_cache; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 57762306a36Sopenharmony_ci if (c->delivery_system == SYS_DVBT || 57862306a36Sopenharmony_ci c->delivery_system == SYS_DVBT2) { 57962306a36Sopenharmony_ci ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &level); 58062306a36Sopenharmony_ci } else { 58162306a36Sopenharmony_ci pr_debug("invalid system\n"); 58262306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 58362306a36Sopenharmony_ci return -EINVAL; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci level /= 125; 58862306a36Sopenharmony_ci /* 58962306a36Sopenharmony_ci * level should be between -105dBm and -30dBm. 59062306a36Sopenharmony_ci * E.g. they should be between: 59162306a36Sopenharmony_ci * -105000/125 = -840 and -30000/125 = -240 59262306a36Sopenharmony_ci */ 59362306a36Sopenharmony_ci level = clamp(level, -840, -240); 59462306a36Sopenharmony_ci /* scale value to 0x0000-0xffff */ 59562306a36Sopenharmony_ci *strength = ((level + 840) * 0xffff) / (-240 + 840); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (ret) 59862306a36Sopenharmony_ci pr_debug("ret = %d\n", ret); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci return ret; 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic int cxd2880_read_snr(struct dvb_frontend *fe, u16 *snr) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci int ret; 60662306a36Sopenharmony_ci int snrvalue = 0; 60762306a36Sopenharmony_ci struct cxd2880_priv *priv = NULL; 60862306a36Sopenharmony_ci struct dtv_frontend_properties *c = NULL; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (!fe || !snr) { 61162306a36Sopenharmony_ci pr_err("invalid arg\n"); 61262306a36Sopenharmony_ci return -EINVAL; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci priv = fe->demodulator_priv; 61662306a36Sopenharmony_ci c = &fe->dtv_property_cache; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 61962306a36Sopenharmony_ci if (c->delivery_system == SYS_DVBT) { 62062306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt_mon_snr(&priv->tnrdmd, 62162306a36Sopenharmony_ci &snrvalue); 62262306a36Sopenharmony_ci } else if (c->delivery_system == SYS_DVBT2) { 62362306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt2_mon_snr(&priv->tnrdmd, 62462306a36Sopenharmony_ci &snrvalue); 62562306a36Sopenharmony_ci } else { 62662306a36Sopenharmony_ci pr_err("invalid system\n"); 62762306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 62862306a36Sopenharmony_ci return -EINVAL; 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci if (snrvalue < 0) 63362306a36Sopenharmony_ci snrvalue = 0; 63462306a36Sopenharmony_ci *snr = snrvalue; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (ret) 63762306a36Sopenharmony_ci pr_debug("ret = %d\n", ret); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci return ret; 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic int cxd2880_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci int ret; 64562306a36Sopenharmony_ci struct cxd2880_priv *priv = NULL; 64662306a36Sopenharmony_ci struct dtv_frontend_properties *c = NULL; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (!fe || !ucblocks) { 64962306a36Sopenharmony_ci pr_err("invalid arg\n"); 65062306a36Sopenharmony_ci return -EINVAL; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci priv = fe->demodulator_priv; 65462306a36Sopenharmony_ci c = &fe->dtv_property_cache; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 65762306a36Sopenharmony_ci if (c->delivery_system == SYS_DVBT) { 65862306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt_mon_packet_error_number(&priv->tnrdmd, 65962306a36Sopenharmony_ci ucblocks); 66062306a36Sopenharmony_ci } else if (c->delivery_system == SYS_DVBT2) { 66162306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt2_mon_packet_error_number(&priv->tnrdmd, 66262306a36Sopenharmony_ci ucblocks); 66362306a36Sopenharmony_ci } else { 66462306a36Sopenharmony_ci pr_err("invalid system\n"); 66562306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 66662306a36Sopenharmony_ci return -EINVAL; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (ret) 67162306a36Sopenharmony_ci pr_debug("ret = %d\n", ret); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci return ret; 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic int cxd2880_read_ber(struct dvb_frontend *fe, u32 *ber) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci *ber = 0; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic int cxd2880_set_ber_per_period_t(struct dvb_frontend *fe) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci int ret; 68662306a36Sopenharmony_ci struct cxd2880_priv *priv; 68762306a36Sopenharmony_ci struct cxd2880_dvbt_tpsinfo info; 68862306a36Sopenharmony_ci enum cxd2880_dtv_bandwidth bw; 68962306a36Sopenharmony_ci u32 pre_ber_rate = 0; 69062306a36Sopenharmony_ci u32 post_ber_rate = 0; 69162306a36Sopenharmony_ci u32 ucblock_rate = 0; 69262306a36Sopenharmony_ci u32 mes_exp = 0; 69362306a36Sopenharmony_ci static const int cr_table[5] = {31500, 42000, 47250, 52500, 55125}; 69462306a36Sopenharmony_ci static const int denominator_tbl[4] = {125664, 129472, 137088, 152320}; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (!fe) { 69762306a36Sopenharmony_ci pr_err("invalid arg\n"); 69862306a36Sopenharmony_ci return -EINVAL; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci priv = fe->demodulator_priv; 70262306a36Sopenharmony_ci bw = priv->dvbt_tune_param.bandwidth; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, 70562306a36Sopenharmony_ci &info); 70662306a36Sopenharmony_ci if (ret) { 70762306a36Sopenharmony_ci pr_err("tps monitor error ret = %d\n", ret); 70862306a36Sopenharmony_ci info.hierarchy = CXD2880_DVBT_HIERARCHY_NON; 70962306a36Sopenharmony_ci info.constellation = CXD2880_DVBT_CONSTELLATION_QPSK; 71062306a36Sopenharmony_ci info.guard = CXD2880_DVBT_GUARD_1_4; 71162306a36Sopenharmony_ci info.rate_hp = CXD2880_DVBT_CODERATE_1_2; 71262306a36Sopenharmony_ci info.rate_lp = CXD2880_DVBT_CODERATE_1_2; 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci if (info.hierarchy == CXD2880_DVBT_HIERARCHY_NON) { 71662306a36Sopenharmony_ci pre_ber_rate = 63000000 * bw * (info.constellation * 2 + 2) / 71762306a36Sopenharmony_ci denominator_tbl[info.guard]; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * 72062306a36Sopenharmony_ci (info.constellation * 2 + 2) / 72162306a36Sopenharmony_ci denominator_tbl[info.guard]; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci ucblock_rate = 875 * cr_table[info.rate_hp] * bw * 72462306a36Sopenharmony_ci (info.constellation * 2 + 2) / 72562306a36Sopenharmony_ci denominator_tbl[info.guard]; 72662306a36Sopenharmony_ci } else { 72762306a36Sopenharmony_ci u8 data = 0; 72862306a36Sopenharmony_ci struct cxd2880_tnrdmd *tnrdmd = &priv->tnrdmd; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci ret = tnrdmd->io->write_reg(tnrdmd->io, 73162306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 73262306a36Sopenharmony_ci 0x00, 0x10); 73362306a36Sopenharmony_ci if (!ret) { 73462306a36Sopenharmony_ci ret = tnrdmd->io->read_regs(tnrdmd->io, 73562306a36Sopenharmony_ci CXD2880_IO_TGT_DMD, 73662306a36Sopenharmony_ci 0x67, &data, 1); 73762306a36Sopenharmony_ci if (ret) 73862306a36Sopenharmony_ci data = 0x00; 73962306a36Sopenharmony_ci } else { 74062306a36Sopenharmony_ci data = 0x00; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (data & 0x01) { /* Low priority */ 74462306a36Sopenharmony_ci pre_ber_rate = 74562306a36Sopenharmony_ci 63000000 * bw * (info.constellation * 2 + 2) / 74662306a36Sopenharmony_ci denominator_tbl[info.guard]; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci post_ber_rate = 1000 * cr_table[info.rate_lp] * bw * 74962306a36Sopenharmony_ci (info.constellation * 2 + 2) / 75062306a36Sopenharmony_ci denominator_tbl[info.guard]; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_lp] * 75362306a36Sopenharmony_ci bw * (info.constellation * 2 + 2) / 75462306a36Sopenharmony_ci denominator_tbl[info.guard]; 75562306a36Sopenharmony_ci } else { /* High priority */ 75662306a36Sopenharmony_ci pre_ber_rate = 75762306a36Sopenharmony_ci 63000000 * bw * 2 / denominator_tbl[info.guard]; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * 2 / 76062306a36Sopenharmony_ci denominator_tbl[info.guard]; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_hp] * 76362306a36Sopenharmony_ci bw * 2 / denominator_tbl[info.guard]; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci mes_exp = pre_ber_rate < 8192 ? 8 : intlog2(pre_ber_rate) >> 24; 76862306a36Sopenharmony_ci priv->pre_ber_interval = 76962306a36Sopenharmony_ci ((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) / 77062306a36Sopenharmony_ci pre_ber_rate; 77162306a36Sopenharmony_ci cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, 77262306a36Sopenharmony_ci CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD, 77362306a36Sopenharmony_ci mes_exp == 8 ? 0 : mes_exp - 12); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci mes_exp = intlog2(post_ber_rate) >> 24; 77662306a36Sopenharmony_ci priv->post_ber_interval = 77762306a36Sopenharmony_ci ((1U << mes_exp) * 1000 + (post_ber_rate / 2)) / 77862306a36Sopenharmony_ci post_ber_rate; 77962306a36Sopenharmony_ci cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, 78062306a36Sopenharmony_ci CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD, 78162306a36Sopenharmony_ci mes_exp); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci mes_exp = intlog2(ucblock_rate) >> 24; 78462306a36Sopenharmony_ci priv->ucblock_interval = 78562306a36Sopenharmony_ci ((1U << mes_exp) * 1000 + (ucblock_rate / 2)) / 78662306a36Sopenharmony_ci ucblock_rate; 78762306a36Sopenharmony_ci cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, 78862306a36Sopenharmony_ci CXD2880_TNRDMD_CFG_DVBT_PER_MES, 78962306a36Sopenharmony_ci mes_exp); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci return 0; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic int cxd2880_set_ber_per_period_t2(struct dvb_frontend *fe) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci int ret; 79762306a36Sopenharmony_ci struct cxd2880_priv *priv; 79862306a36Sopenharmony_ci struct cxd2880_dvbt2_l1pre l1pre; 79962306a36Sopenharmony_ci struct cxd2880_dvbt2_l1post l1post; 80062306a36Sopenharmony_ci struct cxd2880_dvbt2_plp plp; 80162306a36Sopenharmony_ci struct cxd2880_dvbt2_bbheader bbheader; 80262306a36Sopenharmony_ci enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; 80362306a36Sopenharmony_ci u32 pre_ber_rate = 0; 80462306a36Sopenharmony_ci u32 post_ber_rate = 0; 80562306a36Sopenharmony_ci u32 ucblock_rate = 0; 80662306a36Sopenharmony_ci u32 mes_exp = 0; 80762306a36Sopenharmony_ci u32 term_a = 0; 80862306a36Sopenharmony_ci u32 term_b = 0; 80962306a36Sopenharmony_ci u32 denominator = 0; 81062306a36Sopenharmony_ci static const u32 gi_tbl[7] = {32, 64, 128, 256, 8, 152, 76}; 81162306a36Sopenharmony_ci static const u8 n_tbl[6] = {8, 2, 4, 16, 1, 1}; 81262306a36Sopenharmony_ci static const u8 mode_tbl[6] = {2, 8, 4, 1, 16, 32}; 81362306a36Sopenharmony_ci static const u32 kbch_tbl[2][8] = { 81462306a36Sopenharmony_ci {6952, 9472, 10552, 11632, 12352, 13072, 5152, 6232}, 81562306a36Sopenharmony_ci {32128, 38608, 42960, 48328, 51568, 53760, 0, 0} 81662306a36Sopenharmony_ci }; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci if (!fe) { 81962306a36Sopenharmony_ci pr_err("invalid arg\n"); 82062306a36Sopenharmony_ci return -EINVAL; 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci priv = fe->demodulator_priv; 82462306a36Sopenharmony_ci bw = priv->dvbt2_tune_param.bandwidth; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre); 82762306a36Sopenharmony_ci if (ret) { 82862306a36Sopenharmony_ci pr_info("l1 pre error\n"); 82962306a36Sopenharmony_ci goto error_ber_setting; 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt2_mon_active_plp(&priv->tnrdmd, 83362306a36Sopenharmony_ci CXD2880_DVBT2_PLP_DATA, &plp); 83462306a36Sopenharmony_ci if (ret) { 83562306a36Sopenharmony_ci pr_info("plp info error\n"); 83662306a36Sopenharmony_ci goto error_ber_setting; 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt2_mon_l1_post(&priv->tnrdmd, &l1post); 84062306a36Sopenharmony_ci if (ret) { 84162306a36Sopenharmony_ci pr_info("l1 post error\n"); 84262306a36Sopenharmony_ci goto error_ber_setting; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci term_a = 84662306a36Sopenharmony_ci (mode_tbl[l1pre.fft_mode] * (1024 + gi_tbl[l1pre.gi])) * 84762306a36Sopenharmony_ci (l1pre.num_symbols + n_tbl[l1pre.fft_mode]) + 2048; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (l1pre.mixed && l1post.fef_intvl) { 85062306a36Sopenharmony_ci term_b = (l1post.fef_length + (l1post.fef_intvl / 2)) / 85162306a36Sopenharmony_ci l1post.fef_intvl; 85262306a36Sopenharmony_ci } else { 85362306a36Sopenharmony_ci term_b = 0; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci switch (bw) { 85762306a36Sopenharmony_ci case CXD2880_DTV_BW_1_7_MHZ: 85862306a36Sopenharmony_ci denominator = ((term_a + term_b) * 71 + (131 / 2)) / 131; 85962306a36Sopenharmony_ci break; 86062306a36Sopenharmony_ci case CXD2880_DTV_BW_5_MHZ: 86162306a36Sopenharmony_ci denominator = ((term_a + term_b) * 7 + 20) / 40; 86262306a36Sopenharmony_ci break; 86362306a36Sopenharmony_ci case CXD2880_DTV_BW_6_MHZ: 86462306a36Sopenharmony_ci denominator = ((term_a + term_b) * 7 + 24) / 48; 86562306a36Sopenharmony_ci break; 86662306a36Sopenharmony_ci case CXD2880_DTV_BW_7_MHZ: 86762306a36Sopenharmony_ci denominator = ((term_a + term_b) + 4) / 8; 86862306a36Sopenharmony_ci break; 86962306a36Sopenharmony_ci case CXD2880_DTV_BW_8_MHZ: 87062306a36Sopenharmony_ci default: 87162306a36Sopenharmony_ci denominator = ((term_a + term_b) * 7 + 32) / 64; 87262306a36Sopenharmony_ci break; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci if (plp.til_type && plp.til_len) { 87662306a36Sopenharmony_ci pre_ber_rate = 87762306a36Sopenharmony_ci (plp.num_blocks_max * 1000000 + (denominator / 2)) / 87862306a36Sopenharmony_ci denominator; 87962306a36Sopenharmony_ci pre_ber_rate = (pre_ber_rate + (plp.til_len / 2)) / 88062306a36Sopenharmony_ci plp.til_len; 88162306a36Sopenharmony_ci } else { 88262306a36Sopenharmony_ci pre_ber_rate = 88362306a36Sopenharmony_ci (plp.num_blocks_max * 1000000 + (denominator / 2)) / 88462306a36Sopenharmony_ci denominator; 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci post_ber_rate = pre_ber_rate; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci mes_exp = intlog2(pre_ber_rate) >> 24; 89062306a36Sopenharmony_ci priv->pre_ber_interval = 89162306a36Sopenharmony_ci ((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) / 89262306a36Sopenharmony_ci pre_ber_rate; 89362306a36Sopenharmony_ci cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, 89462306a36Sopenharmony_ci CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, 89562306a36Sopenharmony_ci mes_exp); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci mes_exp = intlog2(post_ber_rate) >> 24; 89862306a36Sopenharmony_ci priv->post_ber_interval = 89962306a36Sopenharmony_ci ((1U << mes_exp) * 1000 + (post_ber_rate / 2)) / 90062306a36Sopenharmony_ci post_ber_rate; 90162306a36Sopenharmony_ci cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, 90262306a36Sopenharmony_ci CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, 90362306a36Sopenharmony_ci mes_exp); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt2_mon_bbheader(&priv->tnrdmd, 90662306a36Sopenharmony_ci CXD2880_DVBT2_PLP_DATA, 90762306a36Sopenharmony_ci &bbheader); 90862306a36Sopenharmony_ci if (ret) { 90962306a36Sopenharmony_ci pr_info("bb header error\n"); 91062306a36Sopenharmony_ci goto error_ucblock_setting; 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_NM) { 91462306a36Sopenharmony_ci if (!bbheader.issy_indicator) { 91562306a36Sopenharmony_ci ucblock_rate = 91662306a36Sopenharmony_ci (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + 91762306a36Sopenharmony_ci 752) / 1504; 91862306a36Sopenharmony_ci } else { 91962306a36Sopenharmony_ci ucblock_rate = 92062306a36Sopenharmony_ci (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + 92162306a36Sopenharmony_ci 764) / 1528; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci } else if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_HEM) { 92462306a36Sopenharmony_ci ucblock_rate = 92562306a36Sopenharmony_ci (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + 748) / 92662306a36Sopenharmony_ci 1496; 92762306a36Sopenharmony_ci } else { 92862306a36Sopenharmony_ci pr_info("plp mode is not Normal or HEM\n"); 92962306a36Sopenharmony_ci goto error_ucblock_setting; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci mes_exp = intlog2(ucblock_rate) >> 24; 93362306a36Sopenharmony_ci priv->ucblock_interval = 93462306a36Sopenharmony_ci ((1U << mes_exp) * 1000 + (ucblock_rate / 2)) / 93562306a36Sopenharmony_ci ucblock_rate; 93662306a36Sopenharmony_ci cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, 93762306a36Sopenharmony_ci CXD2880_TNRDMD_CFG_DVBT2_PER_MES, 93862306a36Sopenharmony_ci mes_exp); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci return 0; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_cierror_ber_setting: 94362306a36Sopenharmony_ci priv->pre_ber_interval = 1000; 94462306a36Sopenharmony_ci cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, 94562306a36Sopenharmony_ci CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, 0); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci priv->post_ber_interval = 1000; 94862306a36Sopenharmony_ci cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, 94962306a36Sopenharmony_ci CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, 0); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_cierror_ucblock_setting: 95262306a36Sopenharmony_ci priv->ucblock_interval = 1000; 95362306a36Sopenharmony_ci cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, 95462306a36Sopenharmony_ci CXD2880_TNRDMD_CFG_DVBT2_PER_MES, 8); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci return 0; 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic int cxd2880_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd, 96062306a36Sopenharmony_ci struct cxd2880_dvbt_tune_param 96162306a36Sopenharmony_ci *tune_param) 96262306a36Sopenharmony_ci{ 96362306a36Sopenharmony_ci int ret; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci if (!tnr_dmd || !tune_param) 96662306a36Sopenharmony_ci return -EINVAL; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 96962306a36Sopenharmony_ci return -EINVAL; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && 97262306a36Sopenharmony_ci tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 97362306a36Sopenharmony_ci return -EINVAL; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci atomic_set(&tnr_dmd->cancel, 0); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci if (tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ && 97862306a36Sopenharmony_ci tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ && 97962306a36Sopenharmony_ci tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ && 98062306a36Sopenharmony_ci tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ) { 98162306a36Sopenharmony_ci return -ENOTTY; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt_tune1(tnr_dmd, tune_param); 98562306a36Sopenharmony_ci if (ret) 98662306a36Sopenharmony_ci return ret; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000, 98962306a36Sopenharmony_ci CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci return cxd2880_tnrdmd_dvbt_tune2(tnr_dmd, tune_param); 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_cistatic int cxd2880_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd, 99562306a36Sopenharmony_ci struct cxd2880_dvbt2_tune_param 99662306a36Sopenharmony_ci *tune_param) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci int ret; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci if (!tnr_dmd || !tune_param) 100162306a36Sopenharmony_ci return -EINVAL; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) 100462306a36Sopenharmony_ci return -EINVAL; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && 100762306a36Sopenharmony_ci tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) 100862306a36Sopenharmony_ci return -EINVAL; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci atomic_set(&tnr_dmd->cancel, 0); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if (tune_param->bandwidth != CXD2880_DTV_BW_1_7_MHZ && 101362306a36Sopenharmony_ci tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ && 101462306a36Sopenharmony_ci tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ && 101562306a36Sopenharmony_ci tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ && 101662306a36Sopenharmony_ci tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ) { 101762306a36Sopenharmony_ci return -ENOTTY; 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci if (tune_param->profile != CXD2880_DVBT2_PROFILE_BASE && 102162306a36Sopenharmony_ci tune_param->profile != CXD2880_DVBT2_PROFILE_LITE) 102262306a36Sopenharmony_ci return -EINVAL; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt2_tune1(tnr_dmd, tune_param); 102562306a36Sopenharmony_ci if (ret) 102662306a36Sopenharmony_ci return ret; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000, 102962306a36Sopenharmony_ci CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci return cxd2880_tnrdmd_dvbt2_tune2(tnr_dmd, tune_param); 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_cistatic int cxd2880_set_frontend(struct dvb_frontend *fe) 103562306a36Sopenharmony_ci{ 103662306a36Sopenharmony_ci int ret; 103762306a36Sopenharmony_ci struct dtv_frontend_properties *c; 103862306a36Sopenharmony_ci struct cxd2880_priv *priv; 103962306a36Sopenharmony_ci enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci if (!fe) { 104262306a36Sopenharmony_ci pr_err("invalid arg\n"); 104362306a36Sopenharmony_ci return -EINVAL; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci priv = fe->demodulator_priv; 104762306a36Sopenharmony_ci c = &fe->dtv_property_cache; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 105062306a36Sopenharmony_ci c->pre_bit_error.stat[0].uvalue = 0; 105162306a36Sopenharmony_ci c->pre_bit_error.len = 1; 105262306a36Sopenharmony_ci c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 105362306a36Sopenharmony_ci c->pre_bit_count.stat[0].uvalue = 0; 105462306a36Sopenharmony_ci c->pre_bit_count.len = 1; 105562306a36Sopenharmony_ci c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 105662306a36Sopenharmony_ci c->post_bit_error.stat[0].uvalue = 0; 105762306a36Sopenharmony_ci c->post_bit_error.len = 1; 105862306a36Sopenharmony_ci c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 105962306a36Sopenharmony_ci c->post_bit_count.stat[0].uvalue = 0; 106062306a36Sopenharmony_ci c->post_bit_count.len = 1; 106162306a36Sopenharmony_ci c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 106262306a36Sopenharmony_ci c->block_error.stat[0].uvalue = 0; 106362306a36Sopenharmony_ci c->block_error.len = 1; 106462306a36Sopenharmony_ci c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 106562306a36Sopenharmony_ci c->block_count.stat[0].uvalue = 0; 106662306a36Sopenharmony_ci c->block_count.len = 1; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci switch (c->bandwidth_hz) { 106962306a36Sopenharmony_ci case 1712000: 107062306a36Sopenharmony_ci bw = CXD2880_DTV_BW_1_7_MHZ; 107162306a36Sopenharmony_ci break; 107262306a36Sopenharmony_ci case 5000000: 107362306a36Sopenharmony_ci bw = CXD2880_DTV_BW_5_MHZ; 107462306a36Sopenharmony_ci break; 107562306a36Sopenharmony_ci case 6000000: 107662306a36Sopenharmony_ci bw = CXD2880_DTV_BW_6_MHZ; 107762306a36Sopenharmony_ci break; 107862306a36Sopenharmony_ci case 7000000: 107962306a36Sopenharmony_ci bw = CXD2880_DTV_BW_7_MHZ; 108062306a36Sopenharmony_ci break; 108162306a36Sopenharmony_ci case 8000000: 108262306a36Sopenharmony_ci bw = CXD2880_DTV_BW_8_MHZ; 108362306a36Sopenharmony_ci break; 108462306a36Sopenharmony_ci default: 108562306a36Sopenharmony_ci return -EINVAL; 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci priv->s = 0; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci pr_info("sys:%d freq:%d bw:%d\n", 109162306a36Sopenharmony_ci c->delivery_system, c->frequency, bw); 109262306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 109362306a36Sopenharmony_ci if (c->delivery_system == SYS_DVBT) { 109462306a36Sopenharmony_ci priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT; 109562306a36Sopenharmony_ci priv->dvbt_tune_param.center_freq_khz = c->frequency / 1000; 109662306a36Sopenharmony_ci priv->dvbt_tune_param.bandwidth = bw; 109762306a36Sopenharmony_ci priv->dvbt_tune_param.profile = CXD2880_DVBT_PROFILE_HP; 109862306a36Sopenharmony_ci ret = cxd2880_dvbt_tune(&priv->tnrdmd, 109962306a36Sopenharmony_ci &priv->dvbt_tune_param); 110062306a36Sopenharmony_ci } else if (c->delivery_system == SYS_DVBT2) { 110162306a36Sopenharmony_ci priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT2; 110262306a36Sopenharmony_ci priv->dvbt2_tune_param.center_freq_khz = c->frequency / 1000; 110362306a36Sopenharmony_ci priv->dvbt2_tune_param.bandwidth = bw; 110462306a36Sopenharmony_ci priv->dvbt2_tune_param.data_plp_id = (u16)c->stream_id; 110562306a36Sopenharmony_ci priv->dvbt2_tune_param.profile = CXD2880_DVBT2_PROFILE_BASE; 110662306a36Sopenharmony_ci ret = cxd2880_dvbt2_tune(&priv->tnrdmd, 110762306a36Sopenharmony_ci &priv->dvbt2_tune_param); 110862306a36Sopenharmony_ci } else { 110962306a36Sopenharmony_ci pr_err("invalid system\n"); 111062306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 111162306a36Sopenharmony_ci return -EINVAL; 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci pr_info("tune result %d\n", ret); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci return ret; 111862306a36Sopenharmony_ci} 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cistatic int cxd2880_get_stats(struct dvb_frontend *fe, 112162306a36Sopenharmony_ci enum fe_status status) 112262306a36Sopenharmony_ci{ 112362306a36Sopenharmony_ci struct cxd2880_priv *priv = NULL; 112462306a36Sopenharmony_ci struct dtv_frontend_properties *c = NULL; 112562306a36Sopenharmony_ci u32 pre_bit_err = 0, pre_bit_count = 0; 112662306a36Sopenharmony_ci u32 post_bit_err = 0, post_bit_count = 0; 112762306a36Sopenharmony_ci u32 block_err = 0, block_count = 0; 112862306a36Sopenharmony_ci int ret; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci if (!fe) { 113162306a36Sopenharmony_ci pr_err("invalid arg\n"); 113262306a36Sopenharmony_ci return -EINVAL; 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci priv = fe->demodulator_priv; 113662306a36Sopenharmony_ci c = &fe->dtv_property_cache; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci if (!(status & FE_HAS_LOCK) || !(status & FE_HAS_CARRIER)) { 113962306a36Sopenharmony_ci c->pre_bit_error.len = 1; 114062306a36Sopenharmony_ci c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 114162306a36Sopenharmony_ci c->pre_bit_count.len = 1; 114262306a36Sopenharmony_ci c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 114362306a36Sopenharmony_ci c->post_bit_error.len = 1; 114462306a36Sopenharmony_ci c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 114562306a36Sopenharmony_ci c->post_bit_count.len = 1; 114662306a36Sopenharmony_ci c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 114762306a36Sopenharmony_ci c->block_error.len = 1; 114862306a36Sopenharmony_ci c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 114962306a36Sopenharmony_ci c->block_count.len = 1; 115062306a36Sopenharmony_ci c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci return 0; 115362306a36Sopenharmony_ci } 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci if (time_after(jiffies, priv->pre_ber_update)) { 115662306a36Sopenharmony_ci priv->pre_ber_update = 115762306a36Sopenharmony_ci jiffies + msecs_to_jiffies(priv->pre_ber_interval); 115862306a36Sopenharmony_ci if (c->delivery_system == SYS_DVBT) { 115962306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 116062306a36Sopenharmony_ci ret = cxd2880_pre_bit_err_t(&priv->tnrdmd, 116162306a36Sopenharmony_ci &pre_bit_err, 116262306a36Sopenharmony_ci &pre_bit_count); 116362306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 116462306a36Sopenharmony_ci } else if (c->delivery_system == SYS_DVBT2) { 116562306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 116662306a36Sopenharmony_ci ret = cxd2880_pre_bit_err_t2(&priv->tnrdmd, 116762306a36Sopenharmony_ci &pre_bit_err, 116862306a36Sopenharmony_ci &pre_bit_count); 116962306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 117062306a36Sopenharmony_ci } else { 117162306a36Sopenharmony_ci return -EINVAL; 117262306a36Sopenharmony_ci } 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci if (!ret) { 117562306a36Sopenharmony_ci c->pre_bit_error.len = 1; 117662306a36Sopenharmony_ci c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; 117762306a36Sopenharmony_ci c->pre_bit_error.stat[0].uvalue += pre_bit_err; 117862306a36Sopenharmony_ci c->pre_bit_count.len = 1; 117962306a36Sopenharmony_ci c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; 118062306a36Sopenharmony_ci c->pre_bit_count.stat[0].uvalue += pre_bit_count; 118162306a36Sopenharmony_ci } else { 118262306a36Sopenharmony_ci c->pre_bit_error.len = 1; 118362306a36Sopenharmony_ci c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 118462306a36Sopenharmony_ci c->pre_bit_count.len = 1; 118562306a36Sopenharmony_ci c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 118662306a36Sopenharmony_ci pr_debug("pre_bit_error_t failed %d\n", ret); 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci if (time_after(jiffies, priv->post_ber_update)) { 119162306a36Sopenharmony_ci priv->post_ber_update = 119262306a36Sopenharmony_ci jiffies + msecs_to_jiffies(priv->post_ber_interval); 119362306a36Sopenharmony_ci if (c->delivery_system == SYS_DVBT) { 119462306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 119562306a36Sopenharmony_ci ret = cxd2880_post_bit_err_t(&priv->tnrdmd, 119662306a36Sopenharmony_ci &post_bit_err, 119762306a36Sopenharmony_ci &post_bit_count); 119862306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 119962306a36Sopenharmony_ci } else if (c->delivery_system == SYS_DVBT2) { 120062306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 120162306a36Sopenharmony_ci ret = cxd2880_post_bit_err_t2(&priv->tnrdmd, 120262306a36Sopenharmony_ci &post_bit_err, 120362306a36Sopenharmony_ci &post_bit_count); 120462306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 120562306a36Sopenharmony_ci } else { 120662306a36Sopenharmony_ci return -EINVAL; 120762306a36Sopenharmony_ci } 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci if (!ret) { 121062306a36Sopenharmony_ci c->post_bit_error.len = 1; 121162306a36Sopenharmony_ci c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; 121262306a36Sopenharmony_ci c->post_bit_error.stat[0].uvalue += post_bit_err; 121362306a36Sopenharmony_ci c->post_bit_count.len = 1; 121462306a36Sopenharmony_ci c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; 121562306a36Sopenharmony_ci c->post_bit_count.stat[0].uvalue += post_bit_count; 121662306a36Sopenharmony_ci } else { 121762306a36Sopenharmony_ci c->post_bit_error.len = 1; 121862306a36Sopenharmony_ci c->post_bit_error.stat[0].scale = 121962306a36Sopenharmony_ci FE_SCALE_NOT_AVAILABLE; 122062306a36Sopenharmony_ci c->post_bit_count.len = 1; 122162306a36Sopenharmony_ci c->post_bit_count.stat[0].scale = 122262306a36Sopenharmony_ci FE_SCALE_NOT_AVAILABLE; 122362306a36Sopenharmony_ci pr_debug("post_bit_err_t %d\n", ret); 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci if (time_after(jiffies, priv->ucblock_update)) { 122862306a36Sopenharmony_ci priv->ucblock_update = 122962306a36Sopenharmony_ci jiffies + msecs_to_jiffies(priv->ucblock_interval); 123062306a36Sopenharmony_ci if (c->delivery_system == SYS_DVBT) { 123162306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 123262306a36Sopenharmony_ci ret = cxd2880_read_block_err_t(&priv->tnrdmd, 123362306a36Sopenharmony_ci &block_err, 123462306a36Sopenharmony_ci &block_count); 123562306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 123662306a36Sopenharmony_ci } else if (c->delivery_system == SYS_DVBT2) { 123762306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 123862306a36Sopenharmony_ci ret = cxd2880_read_block_err_t2(&priv->tnrdmd, 123962306a36Sopenharmony_ci &block_err, 124062306a36Sopenharmony_ci &block_count); 124162306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 124262306a36Sopenharmony_ci } else { 124362306a36Sopenharmony_ci return -EINVAL; 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci if (!ret) { 124662306a36Sopenharmony_ci c->block_error.len = 1; 124762306a36Sopenharmony_ci c->block_error.stat[0].scale = FE_SCALE_COUNTER; 124862306a36Sopenharmony_ci c->block_error.stat[0].uvalue += block_err; 124962306a36Sopenharmony_ci c->block_count.len = 1; 125062306a36Sopenharmony_ci c->block_count.stat[0].scale = FE_SCALE_COUNTER; 125162306a36Sopenharmony_ci c->block_count.stat[0].uvalue += block_count; 125262306a36Sopenharmony_ci } else { 125362306a36Sopenharmony_ci c->block_error.len = 1; 125462306a36Sopenharmony_ci c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 125562306a36Sopenharmony_ci c->block_count.len = 1; 125662306a36Sopenharmony_ci c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 125762306a36Sopenharmony_ci pr_debug("read_block_err_t %d\n", ret); 125862306a36Sopenharmony_ci } 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci return 0; 126262306a36Sopenharmony_ci} 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_cistatic int cxd2880_check_l1post_plp(struct dvb_frontend *fe) 126562306a36Sopenharmony_ci{ 126662306a36Sopenharmony_ci u8 valid = 0; 126762306a36Sopenharmony_ci u8 plp_not_found; 126862306a36Sopenharmony_ci int ret; 126962306a36Sopenharmony_ci struct cxd2880_priv *priv = NULL; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci if (!fe) { 127262306a36Sopenharmony_ci pr_err("invalid arg\n"); 127362306a36Sopenharmony_ci return -EINVAL; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci priv = fe->demodulator_priv; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt2_check_l1post_valid(&priv->tnrdmd, 127962306a36Sopenharmony_ci &valid); 128062306a36Sopenharmony_ci if (ret) 128162306a36Sopenharmony_ci return ret; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci if (!valid) 128462306a36Sopenharmony_ci return -EAGAIN; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt2_mon_data_plp_error(&priv->tnrdmd, 128762306a36Sopenharmony_ci &plp_not_found); 128862306a36Sopenharmony_ci if (ret) 128962306a36Sopenharmony_ci return ret; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci if (plp_not_found) { 129262306a36Sopenharmony_ci priv->dvbt2_tune_param.tune_info = 129362306a36Sopenharmony_ci CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID; 129462306a36Sopenharmony_ci } else { 129562306a36Sopenharmony_ci priv->dvbt2_tune_param.tune_info = 129662306a36Sopenharmony_ci CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK; 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci return 0; 130062306a36Sopenharmony_ci} 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_cistatic int cxd2880_read_status(struct dvb_frontend *fe, 130362306a36Sopenharmony_ci enum fe_status *status) 130462306a36Sopenharmony_ci{ 130562306a36Sopenharmony_ci int ret; 130662306a36Sopenharmony_ci u8 sync = 0; 130762306a36Sopenharmony_ci u8 lock = 0; 130862306a36Sopenharmony_ci u8 unlock = 0; 130962306a36Sopenharmony_ci struct cxd2880_priv *priv = NULL; 131062306a36Sopenharmony_ci struct dtv_frontend_properties *c = NULL; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci if (!fe || !status) { 131362306a36Sopenharmony_ci pr_err("invalid arg\n"); 131462306a36Sopenharmony_ci return -EINVAL; 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci priv = fe->demodulator_priv; 131862306a36Sopenharmony_ci c = &fe->dtv_property_cache; 131962306a36Sopenharmony_ci *status = 0; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci if (priv->tnrdmd.state == CXD2880_TNRDMD_STATE_ACTIVE) { 132262306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 132362306a36Sopenharmony_ci if (c->delivery_system == SYS_DVBT) { 132462306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt_mon_sync_stat(&priv->tnrdmd, 132562306a36Sopenharmony_ci &sync, 132662306a36Sopenharmony_ci &lock, 132762306a36Sopenharmony_ci &unlock); 132862306a36Sopenharmony_ci } else if (c->delivery_system == SYS_DVBT2) { 132962306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat(&priv->tnrdmd, 133062306a36Sopenharmony_ci &sync, 133162306a36Sopenharmony_ci &lock, 133262306a36Sopenharmony_ci &unlock); 133362306a36Sopenharmony_ci } else { 133462306a36Sopenharmony_ci pr_err("invalid system"); 133562306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 133662306a36Sopenharmony_ci return -EINVAL; 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 134062306a36Sopenharmony_ci if (ret) { 134162306a36Sopenharmony_ci pr_err("failed. sys = %d\n", priv->tnrdmd.sys); 134262306a36Sopenharmony_ci return ret; 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci if (sync == 6) { 134662306a36Sopenharmony_ci *status = FE_HAS_SIGNAL | 134762306a36Sopenharmony_ci FE_HAS_CARRIER; 134862306a36Sopenharmony_ci } 134962306a36Sopenharmony_ci if (lock) 135062306a36Sopenharmony_ci *status |= FE_HAS_VITERBI | 135162306a36Sopenharmony_ci FE_HAS_SYNC | 135262306a36Sopenharmony_ci FE_HAS_LOCK; 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci pr_debug("status %d\n", *status); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci if (priv->s == 0 && (*status & FE_HAS_LOCK) && 135862306a36Sopenharmony_ci (*status & FE_HAS_CARRIER)) { 135962306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 136062306a36Sopenharmony_ci if (c->delivery_system == SYS_DVBT) { 136162306a36Sopenharmony_ci ret = cxd2880_set_ber_per_period_t(fe); 136262306a36Sopenharmony_ci priv->s = *status; 136362306a36Sopenharmony_ci } else if (c->delivery_system == SYS_DVBT2) { 136462306a36Sopenharmony_ci ret = cxd2880_check_l1post_plp(fe); 136562306a36Sopenharmony_ci if (!ret) { 136662306a36Sopenharmony_ci ret = cxd2880_set_ber_per_period_t2(fe); 136762306a36Sopenharmony_ci priv->s = *status; 136862306a36Sopenharmony_ci } 136962306a36Sopenharmony_ci } else { 137062306a36Sopenharmony_ci pr_err("invalid system\n"); 137162306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 137262306a36Sopenharmony_ci return -EINVAL; 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci cxd2880_get_stats(fe, *status); 137862306a36Sopenharmony_ci return 0; 137962306a36Sopenharmony_ci} 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_cistatic int cxd2880_tune(struct dvb_frontend *fe, 138262306a36Sopenharmony_ci bool retune, 138362306a36Sopenharmony_ci unsigned int mode_flags, 138462306a36Sopenharmony_ci unsigned int *delay, 138562306a36Sopenharmony_ci enum fe_status *status) 138662306a36Sopenharmony_ci{ 138762306a36Sopenharmony_ci int ret; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci if (!fe || !delay || !status) { 139062306a36Sopenharmony_ci pr_err("invalid arg."); 139162306a36Sopenharmony_ci return -EINVAL; 139262306a36Sopenharmony_ci } 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci if (retune) { 139562306a36Sopenharmony_ci ret = cxd2880_set_frontend(fe); 139662306a36Sopenharmony_ci if (ret) { 139762306a36Sopenharmony_ci pr_err("cxd2880_set_frontend failed %d\n", ret); 139862306a36Sopenharmony_ci return ret; 139962306a36Sopenharmony_ci } 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci *delay = HZ / 5; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci return cxd2880_read_status(fe, status); 140562306a36Sopenharmony_ci} 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_cistatic int cxd2880_get_frontend_t(struct dvb_frontend *fe, 140862306a36Sopenharmony_ci struct dtv_frontend_properties *c) 140962306a36Sopenharmony_ci{ 141062306a36Sopenharmony_ci int ret; 141162306a36Sopenharmony_ci struct cxd2880_priv *priv = NULL; 141262306a36Sopenharmony_ci enum cxd2880_dvbt_mode mode = CXD2880_DVBT_MODE_2K; 141362306a36Sopenharmony_ci enum cxd2880_dvbt_guard guard = CXD2880_DVBT_GUARD_1_32; 141462306a36Sopenharmony_ci struct cxd2880_dvbt_tpsinfo tps; 141562306a36Sopenharmony_ci enum cxd2880_tnrdmd_spectrum_sense sense; 141662306a36Sopenharmony_ci u16 snr = 0; 141762306a36Sopenharmony_ci int strength = 0; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci if (!fe || !c) { 142062306a36Sopenharmony_ci pr_err("invalid arg\n"); 142162306a36Sopenharmony_ci return -EINVAL; 142262306a36Sopenharmony_ci } 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci priv = fe->demodulator_priv; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 142762306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt_mon_mode_guard(&priv->tnrdmd, 142862306a36Sopenharmony_ci &mode, &guard); 142962306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 143062306a36Sopenharmony_ci if (!ret) { 143162306a36Sopenharmony_ci switch (mode) { 143262306a36Sopenharmony_ci case CXD2880_DVBT_MODE_2K: 143362306a36Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_2K; 143462306a36Sopenharmony_ci break; 143562306a36Sopenharmony_ci case CXD2880_DVBT_MODE_8K: 143662306a36Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_8K; 143762306a36Sopenharmony_ci break; 143862306a36Sopenharmony_ci default: 143962306a36Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_2K; 144062306a36Sopenharmony_ci pr_debug("transmission mode is invalid %d\n", mode); 144162306a36Sopenharmony_ci break; 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci switch (guard) { 144462306a36Sopenharmony_ci case CXD2880_DVBT_GUARD_1_32: 144562306a36Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_32; 144662306a36Sopenharmony_ci break; 144762306a36Sopenharmony_ci case CXD2880_DVBT_GUARD_1_16: 144862306a36Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_16; 144962306a36Sopenharmony_ci break; 145062306a36Sopenharmony_ci case CXD2880_DVBT_GUARD_1_8: 145162306a36Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_8; 145262306a36Sopenharmony_ci break; 145362306a36Sopenharmony_ci case CXD2880_DVBT_GUARD_1_4: 145462306a36Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_4; 145562306a36Sopenharmony_ci break; 145662306a36Sopenharmony_ci default: 145762306a36Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_32; 145862306a36Sopenharmony_ci pr_debug("guard interval is invalid %d\n", 145962306a36Sopenharmony_ci guard); 146062306a36Sopenharmony_ci break; 146162306a36Sopenharmony_ci } 146262306a36Sopenharmony_ci } else { 146362306a36Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_2K; 146462306a36Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_32; 146562306a36Sopenharmony_ci pr_debug("ModeGuard err %d\n", ret); 146662306a36Sopenharmony_ci } 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 146962306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, &tps); 147062306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 147162306a36Sopenharmony_ci if (!ret) { 147262306a36Sopenharmony_ci switch (tps.hierarchy) { 147362306a36Sopenharmony_ci case CXD2880_DVBT_HIERARCHY_NON: 147462306a36Sopenharmony_ci c->hierarchy = HIERARCHY_NONE; 147562306a36Sopenharmony_ci break; 147662306a36Sopenharmony_ci case CXD2880_DVBT_HIERARCHY_1: 147762306a36Sopenharmony_ci c->hierarchy = HIERARCHY_1; 147862306a36Sopenharmony_ci break; 147962306a36Sopenharmony_ci case CXD2880_DVBT_HIERARCHY_2: 148062306a36Sopenharmony_ci c->hierarchy = HIERARCHY_2; 148162306a36Sopenharmony_ci break; 148262306a36Sopenharmony_ci case CXD2880_DVBT_HIERARCHY_4: 148362306a36Sopenharmony_ci c->hierarchy = HIERARCHY_4; 148462306a36Sopenharmony_ci break; 148562306a36Sopenharmony_ci default: 148662306a36Sopenharmony_ci c->hierarchy = HIERARCHY_NONE; 148762306a36Sopenharmony_ci pr_debug("TPSInfo hierarchy is invalid %d\n", 148862306a36Sopenharmony_ci tps.hierarchy); 148962306a36Sopenharmony_ci break; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci switch (tps.rate_hp) { 149362306a36Sopenharmony_ci case CXD2880_DVBT_CODERATE_1_2: 149462306a36Sopenharmony_ci c->code_rate_HP = FEC_1_2; 149562306a36Sopenharmony_ci break; 149662306a36Sopenharmony_ci case CXD2880_DVBT_CODERATE_2_3: 149762306a36Sopenharmony_ci c->code_rate_HP = FEC_2_3; 149862306a36Sopenharmony_ci break; 149962306a36Sopenharmony_ci case CXD2880_DVBT_CODERATE_3_4: 150062306a36Sopenharmony_ci c->code_rate_HP = FEC_3_4; 150162306a36Sopenharmony_ci break; 150262306a36Sopenharmony_ci case CXD2880_DVBT_CODERATE_5_6: 150362306a36Sopenharmony_ci c->code_rate_HP = FEC_5_6; 150462306a36Sopenharmony_ci break; 150562306a36Sopenharmony_ci case CXD2880_DVBT_CODERATE_7_8: 150662306a36Sopenharmony_ci c->code_rate_HP = FEC_7_8; 150762306a36Sopenharmony_ci break; 150862306a36Sopenharmony_ci default: 150962306a36Sopenharmony_ci c->code_rate_HP = FEC_NONE; 151062306a36Sopenharmony_ci pr_debug("TPSInfo rateHP is invalid %d\n", 151162306a36Sopenharmony_ci tps.rate_hp); 151262306a36Sopenharmony_ci break; 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci switch (tps.rate_lp) { 151562306a36Sopenharmony_ci case CXD2880_DVBT_CODERATE_1_2: 151662306a36Sopenharmony_ci c->code_rate_LP = FEC_1_2; 151762306a36Sopenharmony_ci break; 151862306a36Sopenharmony_ci case CXD2880_DVBT_CODERATE_2_3: 151962306a36Sopenharmony_ci c->code_rate_LP = FEC_2_3; 152062306a36Sopenharmony_ci break; 152162306a36Sopenharmony_ci case CXD2880_DVBT_CODERATE_3_4: 152262306a36Sopenharmony_ci c->code_rate_LP = FEC_3_4; 152362306a36Sopenharmony_ci break; 152462306a36Sopenharmony_ci case CXD2880_DVBT_CODERATE_5_6: 152562306a36Sopenharmony_ci c->code_rate_LP = FEC_5_6; 152662306a36Sopenharmony_ci break; 152762306a36Sopenharmony_ci case CXD2880_DVBT_CODERATE_7_8: 152862306a36Sopenharmony_ci c->code_rate_LP = FEC_7_8; 152962306a36Sopenharmony_ci break; 153062306a36Sopenharmony_ci default: 153162306a36Sopenharmony_ci c->code_rate_LP = FEC_NONE; 153262306a36Sopenharmony_ci pr_debug("TPSInfo rateLP is invalid %d\n", 153362306a36Sopenharmony_ci tps.rate_lp); 153462306a36Sopenharmony_ci break; 153562306a36Sopenharmony_ci } 153662306a36Sopenharmony_ci switch (tps.constellation) { 153762306a36Sopenharmony_ci case CXD2880_DVBT_CONSTELLATION_QPSK: 153862306a36Sopenharmony_ci c->modulation = QPSK; 153962306a36Sopenharmony_ci break; 154062306a36Sopenharmony_ci case CXD2880_DVBT_CONSTELLATION_16QAM: 154162306a36Sopenharmony_ci c->modulation = QAM_16; 154262306a36Sopenharmony_ci break; 154362306a36Sopenharmony_ci case CXD2880_DVBT_CONSTELLATION_64QAM: 154462306a36Sopenharmony_ci c->modulation = QAM_64; 154562306a36Sopenharmony_ci break; 154662306a36Sopenharmony_ci default: 154762306a36Sopenharmony_ci c->modulation = QPSK; 154862306a36Sopenharmony_ci pr_debug("TPSInfo constellation is invalid %d\n", 154962306a36Sopenharmony_ci tps.constellation); 155062306a36Sopenharmony_ci break; 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci } else { 155362306a36Sopenharmony_ci c->hierarchy = HIERARCHY_NONE; 155462306a36Sopenharmony_ci c->code_rate_HP = FEC_NONE; 155562306a36Sopenharmony_ci c->code_rate_LP = FEC_NONE; 155662306a36Sopenharmony_ci c->modulation = QPSK; 155762306a36Sopenharmony_ci pr_debug("TPS info err %d\n", ret); 155862306a36Sopenharmony_ci } 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 156162306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(&priv->tnrdmd, &sense); 156262306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 156362306a36Sopenharmony_ci if (!ret) { 156462306a36Sopenharmony_ci switch (sense) { 156562306a36Sopenharmony_ci case CXD2880_TNRDMD_SPECTRUM_NORMAL: 156662306a36Sopenharmony_ci c->inversion = INVERSION_OFF; 156762306a36Sopenharmony_ci break; 156862306a36Sopenharmony_ci case CXD2880_TNRDMD_SPECTRUM_INV: 156962306a36Sopenharmony_ci c->inversion = INVERSION_ON; 157062306a36Sopenharmony_ci break; 157162306a36Sopenharmony_ci default: 157262306a36Sopenharmony_ci c->inversion = INVERSION_OFF; 157362306a36Sopenharmony_ci pr_debug("spectrum sense is invalid %d\n", sense); 157462306a36Sopenharmony_ci break; 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_ci } else { 157762306a36Sopenharmony_ci c->inversion = INVERSION_OFF; 157862306a36Sopenharmony_ci pr_debug("spectrum_sense %d\n", ret); 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 158262306a36Sopenharmony_ci ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength); 158362306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 158462306a36Sopenharmony_ci if (!ret) { 158562306a36Sopenharmony_ci c->strength.len = 1; 158662306a36Sopenharmony_ci c->strength.stat[0].scale = FE_SCALE_DECIBEL; 158762306a36Sopenharmony_ci c->strength.stat[0].svalue = strength; 158862306a36Sopenharmony_ci } else { 158962306a36Sopenharmony_ci c->strength.len = 1; 159062306a36Sopenharmony_ci c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 159162306a36Sopenharmony_ci pr_debug("mon_rf_lvl %d\n", ret); 159262306a36Sopenharmony_ci } 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci ret = cxd2880_read_snr(fe, &snr); 159562306a36Sopenharmony_ci if (!ret) { 159662306a36Sopenharmony_ci c->cnr.len = 1; 159762306a36Sopenharmony_ci c->cnr.stat[0].scale = FE_SCALE_DECIBEL; 159862306a36Sopenharmony_ci c->cnr.stat[0].svalue = snr; 159962306a36Sopenharmony_ci } else { 160062306a36Sopenharmony_ci c->cnr.len = 1; 160162306a36Sopenharmony_ci c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 160262306a36Sopenharmony_ci pr_debug("read_snr %d\n", ret); 160362306a36Sopenharmony_ci } 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci return 0; 160662306a36Sopenharmony_ci} 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_cistatic int cxd2880_get_frontend_t2(struct dvb_frontend *fe, 160962306a36Sopenharmony_ci struct dtv_frontend_properties *c) 161062306a36Sopenharmony_ci{ 161162306a36Sopenharmony_ci int ret; 161262306a36Sopenharmony_ci struct cxd2880_priv *priv = NULL; 161362306a36Sopenharmony_ci struct cxd2880_dvbt2_l1pre l1pre; 161462306a36Sopenharmony_ci enum cxd2880_dvbt2_plp_code_rate coderate; 161562306a36Sopenharmony_ci enum cxd2880_dvbt2_plp_constell qam; 161662306a36Sopenharmony_ci enum cxd2880_tnrdmd_spectrum_sense sense; 161762306a36Sopenharmony_ci u16 snr = 0; 161862306a36Sopenharmony_ci int strength = 0; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci if (!fe || !c) { 162162306a36Sopenharmony_ci pr_err("invalid arg.\n"); 162262306a36Sopenharmony_ci return -EINVAL; 162362306a36Sopenharmony_ci } 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci priv = fe->demodulator_priv; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 162862306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre); 162962306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 163062306a36Sopenharmony_ci if (!ret) { 163162306a36Sopenharmony_ci switch (l1pre.fft_mode) { 163262306a36Sopenharmony_ci case CXD2880_DVBT2_M2K: 163362306a36Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_2K; 163462306a36Sopenharmony_ci break; 163562306a36Sopenharmony_ci case CXD2880_DVBT2_M8K: 163662306a36Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_8K; 163762306a36Sopenharmony_ci break; 163862306a36Sopenharmony_ci case CXD2880_DVBT2_M4K: 163962306a36Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_4K; 164062306a36Sopenharmony_ci break; 164162306a36Sopenharmony_ci case CXD2880_DVBT2_M1K: 164262306a36Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_1K; 164362306a36Sopenharmony_ci break; 164462306a36Sopenharmony_ci case CXD2880_DVBT2_M16K: 164562306a36Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_16K; 164662306a36Sopenharmony_ci break; 164762306a36Sopenharmony_ci case CXD2880_DVBT2_M32K: 164862306a36Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_32K; 164962306a36Sopenharmony_ci break; 165062306a36Sopenharmony_ci default: 165162306a36Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_2K; 165262306a36Sopenharmony_ci pr_debug("L1Pre fft_mode is invalid %d\n", 165362306a36Sopenharmony_ci l1pre.fft_mode); 165462306a36Sopenharmony_ci break; 165562306a36Sopenharmony_ci } 165662306a36Sopenharmony_ci switch (l1pre.gi) { 165762306a36Sopenharmony_ci case CXD2880_DVBT2_G1_32: 165862306a36Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_32; 165962306a36Sopenharmony_ci break; 166062306a36Sopenharmony_ci case CXD2880_DVBT2_G1_16: 166162306a36Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_16; 166262306a36Sopenharmony_ci break; 166362306a36Sopenharmony_ci case CXD2880_DVBT2_G1_8: 166462306a36Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_8; 166562306a36Sopenharmony_ci break; 166662306a36Sopenharmony_ci case CXD2880_DVBT2_G1_4: 166762306a36Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_4; 166862306a36Sopenharmony_ci break; 166962306a36Sopenharmony_ci case CXD2880_DVBT2_G1_128: 167062306a36Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_128; 167162306a36Sopenharmony_ci break; 167262306a36Sopenharmony_ci case CXD2880_DVBT2_G19_128: 167362306a36Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_19_128; 167462306a36Sopenharmony_ci break; 167562306a36Sopenharmony_ci case CXD2880_DVBT2_G19_256: 167662306a36Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_19_256; 167762306a36Sopenharmony_ci break; 167862306a36Sopenharmony_ci default: 167962306a36Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_32; 168062306a36Sopenharmony_ci pr_debug("L1Pre guard interval is invalid %d\n", 168162306a36Sopenharmony_ci l1pre.gi); 168262306a36Sopenharmony_ci break; 168362306a36Sopenharmony_ci } 168462306a36Sopenharmony_ci } else { 168562306a36Sopenharmony_ci c->transmission_mode = TRANSMISSION_MODE_2K; 168662306a36Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_32; 168762306a36Sopenharmony_ci pr_debug("L1Pre err %d\n", ret); 168862306a36Sopenharmony_ci } 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 169162306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt2_mon_code_rate(&priv->tnrdmd, 169262306a36Sopenharmony_ci CXD2880_DVBT2_PLP_DATA, 169362306a36Sopenharmony_ci &coderate); 169462306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 169562306a36Sopenharmony_ci if (!ret) { 169662306a36Sopenharmony_ci switch (coderate) { 169762306a36Sopenharmony_ci case CXD2880_DVBT2_R1_2: 169862306a36Sopenharmony_ci c->fec_inner = FEC_1_2; 169962306a36Sopenharmony_ci break; 170062306a36Sopenharmony_ci case CXD2880_DVBT2_R3_5: 170162306a36Sopenharmony_ci c->fec_inner = FEC_3_5; 170262306a36Sopenharmony_ci break; 170362306a36Sopenharmony_ci case CXD2880_DVBT2_R2_3: 170462306a36Sopenharmony_ci c->fec_inner = FEC_2_3; 170562306a36Sopenharmony_ci break; 170662306a36Sopenharmony_ci case CXD2880_DVBT2_R3_4: 170762306a36Sopenharmony_ci c->fec_inner = FEC_3_4; 170862306a36Sopenharmony_ci break; 170962306a36Sopenharmony_ci case CXD2880_DVBT2_R4_5: 171062306a36Sopenharmony_ci c->fec_inner = FEC_4_5; 171162306a36Sopenharmony_ci break; 171262306a36Sopenharmony_ci case CXD2880_DVBT2_R5_6: 171362306a36Sopenharmony_ci c->fec_inner = FEC_5_6; 171462306a36Sopenharmony_ci break; 171562306a36Sopenharmony_ci default: 171662306a36Sopenharmony_ci c->fec_inner = FEC_NONE; 171762306a36Sopenharmony_ci pr_debug("CodeRate is invalid %d\n", coderate); 171862306a36Sopenharmony_ci break; 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci } else { 172162306a36Sopenharmony_ci c->fec_inner = FEC_NONE; 172262306a36Sopenharmony_ci pr_debug("CodeRate %d\n", ret); 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 172662306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt2_mon_qam(&priv->tnrdmd, 172762306a36Sopenharmony_ci CXD2880_DVBT2_PLP_DATA, 172862306a36Sopenharmony_ci &qam); 172962306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 173062306a36Sopenharmony_ci if (!ret) { 173162306a36Sopenharmony_ci switch (qam) { 173262306a36Sopenharmony_ci case CXD2880_DVBT2_QPSK: 173362306a36Sopenharmony_ci c->modulation = QPSK; 173462306a36Sopenharmony_ci break; 173562306a36Sopenharmony_ci case CXD2880_DVBT2_QAM16: 173662306a36Sopenharmony_ci c->modulation = QAM_16; 173762306a36Sopenharmony_ci break; 173862306a36Sopenharmony_ci case CXD2880_DVBT2_QAM64: 173962306a36Sopenharmony_ci c->modulation = QAM_64; 174062306a36Sopenharmony_ci break; 174162306a36Sopenharmony_ci case CXD2880_DVBT2_QAM256: 174262306a36Sopenharmony_ci c->modulation = QAM_256; 174362306a36Sopenharmony_ci break; 174462306a36Sopenharmony_ci default: 174562306a36Sopenharmony_ci c->modulation = QPSK; 174662306a36Sopenharmony_ci pr_debug("QAM is invalid %d\n", qam); 174762306a36Sopenharmony_ci break; 174862306a36Sopenharmony_ci } 174962306a36Sopenharmony_ci } else { 175062306a36Sopenharmony_ci c->modulation = QPSK; 175162306a36Sopenharmony_ci pr_debug("QAM %d\n", ret); 175262306a36Sopenharmony_ci } 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 175562306a36Sopenharmony_ci ret = cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(&priv->tnrdmd, &sense); 175662306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 175762306a36Sopenharmony_ci if (!ret) { 175862306a36Sopenharmony_ci switch (sense) { 175962306a36Sopenharmony_ci case CXD2880_TNRDMD_SPECTRUM_NORMAL: 176062306a36Sopenharmony_ci c->inversion = INVERSION_OFF; 176162306a36Sopenharmony_ci break; 176262306a36Sopenharmony_ci case CXD2880_TNRDMD_SPECTRUM_INV: 176362306a36Sopenharmony_ci c->inversion = INVERSION_ON; 176462306a36Sopenharmony_ci break; 176562306a36Sopenharmony_ci default: 176662306a36Sopenharmony_ci c->inversion = INVERSION_OFF; 176762306a36Sopenharmony_ci pr_debug("spectrum sense is invalid %d\n", sense); 176862306a36Sopenharmony_ci break; 176962306a36Sopenharmony_ci } 177062306a36Sopenharmony_ci } else { 177162306a36Sopenharmony_ci c->inversion = INVERSION_OFF; 177262306a36Sopenharmony_ci pr_debug("SpectrumSense %d\n", ret); 177362306a36Sopenharmony_ci } 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci mutex_lock(priv->spi_mutex); 177662306a36Sopenharmony_ci ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength); 177762306a36Sopenharmony_ci mutex_unlock(priv->spi_mutex); 177862306a36Sopenharmony_ci if (!ret) { 177962306a36Sopenharmony_ci c->strength.len = 1; 178062306a36Sopenharmony_ci c->strength.stat[0].scale = FE_SCALE_DECIBEL; 178162306a36Sopenharmony_ci c->strength.stat[0].svalue = strength; 178262306a36Sopenharmony_ci } else { 178362306a36Sopenharmony_ci c->strength.len = 1; 178462306a36Sopenharmony_ci c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 178562306a36Sopenharmony_ci pr_debug("mon_rf_lvl %d\n", ret); 178662306a36Sopenharmony_ci } 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci ret = cxd2880_read_snr(fe, &snr); 178962306a36Sopenharmony_ci if (!ret) { 179062306a36Sopenharmony_ci c->cnr.len = 1; 179162306a36Sopenharmony_ci c->cnr.stat[0].scale = FE_SCALE_DECIBEL; 179262306a36Sopenharmony_ci c->cnr.stat[0].svalue = snr; 179362306a36Sopenharmony_ci } else { 179462306a36Sopenharmony_ci c->cnr.len = 1; 179562306a36Sopenharmony_ci c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 179662306a36Sopenharmony_ci pr_debug("read_snr %d\n", ret); 179762306a36Sopenharmony_ci } 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci return 0; 180062306a36Sopenharmony_ci} 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_cistatic int cxd2880_get_frontend(struct dvb_frontend *fe, 180362306a36Sopenharmony_ci struct dtv_frontend_properties *props) 180462306a36Sopenharmony_ci{ 180562306a36Sopenharmony_ci int ret; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci if (!fe || !props) { 180862306a36Sopenharmony_ci pr_err("invalid arg."); 180962306a36Sopenharmony_ci return -EINVAL; 181062306a36Sopenharmony_ci } 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci pr_debug("system=%d\n", fe->dtv_property_cache.delivery_system); 181362306a36Sopenharmony_ci switch (fe->dtv_property_cache.delivery_system) { 181462306a36Sopenharmony_ci case SYS_DVBT: 181562306a36Sopenharmony_ci ret = cxd2880_get_frontend_t(fe, props); 181662306a36Sopenharmony_ci break; 181762306a36Sopenharmony_ci case SYS_DVBT2: 181862306a36Sopenharmony_ci ret = cxd2880_get_frontend_t2(fe, props); 181962306a36Sopenharmony_ci break; 182062306a36Sopenharmony_ci default: 182162306a36Sopenharmony_ci ret = -EINVAL; 182262306a36Sopenharmony_ci break; 182362306a36Sopenharmony_ci } 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci return ret; 182662306a36Sopenharmony_ci} 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_cistatic enum dvbfe_algo cxd2880_get_frontend_algo(struct dvb_frontend *fe) 182962306a36Sopenharmony_ci{ 183062306a36Sopenharmony_ci return DVBFE_ALGO_HW; 183162306a36Sopenharmony_ci} 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_cistatic struct dvb_frontend_ops cxd2880_dvbt_t2_ops = { 183462306a36Sopenharmony_ci .info = { 183562306a36Sopenharmony_ci .name = "Sony CXD2880", 183662306a36Sopenharmony_ci .frequency_min_hz = 174 * MHz, 183762306a36Sopenharmony_ci .frequency_max_hz = 862 * MHz, 183862306a36Sopenharmony_ci .frequency_stepsize_hz = 1 * kHz, 183962306a36Sopenharmony_ci .caps = FE_CAN_INVERSION_AUTO | 184062306a36Sopenharmony_ci FE_CAN_FEC_1_2 | 184162306a36Sopenharmony_ci FE_CAN_FEC_2_3 | 184262306a36Sopenharmony_ci FE_CAN_FEC_3_4 | 184362306a36Sopenharmony_ci FE_CAN_FEC_4_5 | 184462306a36Sopenharmony_ci FE_CAN_FEC_5_6 | 184562306a36Sopenharmony_ci FE_CAN_FEC_7_8 | 184662306a36Sopenharmony_ci FE_CAN_FEC_AUTO | 184762306a36Sopenharmony_ci FE_CAN_QPSK | 184862306a36Sopenharmony_ci FE_CAN_QAM_16 | 184962306a36Sopenharmony_ci FE_CAN_QAM_32 | 185062306a36Sopenharmony_ci FE_CAN_QAM_64 | 185162306a36Sopenharmony_ci FE_CAN_QAM_128 | 185262306a36Sopenharmony_ci FE_CAN_QAM_256 | 185362306a36Sopenharmony_ci FE_CAN_QAM_AUTO | 185462306a36Sopenharmony_ci FE_CAN_TRANSMISSION_MODE_AUTO | 185562306a36Sopenharmony_ci FE_CAN_GUARD_INTERVAL_AUTO | 185662306a36Sopenharmony_ci FE_CAN_2G_MODULATION | 185762306a36Sopenharmony_ci FE_CAN_RECOVER | 185862306a36Sopenharmony_ci FE_CAN_MUTE_TS, 185962306a36Sopenharmony_ci }, 186062306a36Sopenharmony_ci .delsys = { SYS_DVBT, SYS_DVBT2 }, 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci .release = cxd2880_release, 186362306a36Sopenharmony_ci .init = cxd2880_init, 186462306a36Sopenharmony_ci .sleep = cxd2880_sleep, 186562306a36Sopenharmony_ci .tune = cxd2880_tune, 186662306a36Sopenharmony_ci .set_frontend = cxd2880_set_frontend, 186762306a36Sopenharmony_ci .get_frontend = cxd2880_get_frontend, 186862306a36Sopenharmony_ci .read_status = cxd2880_read_status, 186962306a36Sopenharmony_ci .read_ber = cxd2880_read_ber, 187062306a36Sopenharmony_ci .read_signal_strength = cxd2880_read_signal_strength, 187162306a36Sopenharmony_ci .read_snr = cxd2880_read_snr, 187262306a36Sopenharmony_ci .read_ucblocks = cxd2880_read_ucblocks, 187362306a36Sopenharmony_ci .get_frontend_algo = cxd2880_get_frontend_algo, 187462306a36Sopenharmony_ci}; 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_cistruct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe, 187762306a36Sopenharmony_ci struct cxd2880_config *cfg) 187862306a36Sopenharmony_ci{ 187962306a36Sopenharmony_ci int ret; 188062306a36Sopenharmony_ci enum cxd2880_tnrdmd_chip_id chipid = 188162306a36Sopenharmony_ci CXD2880_TNRDMD_CHIP_ID_UNKNOWN; 188262306a36Sopenharmony_ci static struct cxd2880_priv *priv; 188362306a36Sopenharmony_ci u8 data = 0; 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci if (!fe) { 188662306a36Sopenharmony_ci pr_err("invalid arg.\n"); 188762306a36Sopenharmony_ci return NULL; 188862306a36Sopenharmony_ci } 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci priv = kzalloc(sizeof(struct cxd2880_priv), GFP_KERNEL); 189162306a36Sopenharmony_ci if (!priv) 189262306a36Sopenharmony_ci return NULL; 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci priv->spi = cfg->spi; 189562306a36Sopenharmony_ci priv->spi_mutex = cfg->spi_mutex; 189662306a36Sopenharmony_ci priv->spi_device.spi = cfg->spi; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci memcpy(&fe->ops, &cxd2880_dvbt_t2_ops, 189962306a36Sopenharmony_ci sizeof(struct dvb_frontend_ops)); 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci ret = cxd2880_spi_device_initialize(&priv->spi_device, 190262306a36Sopenharmony_ci CXD2880_SPI_MODE_0, 190362306a36Sopenharmony_ci 55000000); 190462306a36Sopenharmony_ci if (ret) { 190562306a36Sopenharmony_ci pr_err("spi_device_initialize failed. %d\n", ret); 190662306a36Sopenharmony_ci kfree(priv); 190762306a36Sopenharmony_ci return NULL; 190862306a36Sopenharmony_ci } 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci ret = cxd2880_spi_device_create_spi(&priv->cxd2880_spi, 191162306a36Sopenharmony_ci &priv->spi_device); 191262306a36Sopenharmony_ci if (ret) { 191362306a36Sopenharmony_ci pr_err("spi_device_create_spi failed. %d\n", ret); 191462306a36Sopenharmony_ci kfree(priv); 191562306a36Sopenharmony_ci return NULL; 191662306a36Sopenharmony_ci } 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci ret = cxd2880_io_spi_create(&priv->regio, &priv->cxd2880_spi, 0); 191962306a36Sopenharmony_ci if (ret) { 192062306a36Sopenharmony_ci pr_err("io_spi_create failed. %d\n", ret); 192162306a36Sopenharmony_ci kfree(priv); 192262306a36Sopenharmony_ci return NULL; 192362306a36Sopenharmony_ci } 192462306a36Sopenharmony_ci ret = priv->regio.write_reg(&priv->regio, 192562306a36Sopenharmony_ci CXD2880_IO_TGT_SYS, 0x00, 0x00); 192662306a36Sopenharmony_ci if (ret) { 192762306a36Sopenharmony_ci pr_err("set bank to 0x00 failed.\n"); 192862306a36Sopenharmony_ci kfree(priv); 192962306a36Sopenharmony_ci return NULL; 193062306a36Sopenharmony_ci } 193162306a36Sopenharmony_ci ret = priv->regio.read_regs(&priv->regio, 193262306a36Sopenharmony_ci CXD2880_IO_TGT_SYS, 0xfd, &data, 1); 193362306a36Sopenharmony_ci if (ret) { 193462306a36Sopenharmony_ci pr_err("read chip id failed.\n"); 193562306a36Sopenharmony_ci kfree(priv); 193662306a36Sopenharmony_ci return NULL; 193762306a36Sopenharmony_ci } 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci chipid = (enum cxd2880_tnrdmd_chip_id)data; 194062306a36Sopenharmony_ci if (chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X && 194162306a36Sopenharmony_ci chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11) { 194262306a36Sopenharmony_ci pr_err("chip id invalid.\n"); 194362306a36Sopenharmony_ci kfree(priv); 194462306a36Sopenharmony_ci return NULL; 194562306a36Sopenharmony_ci } 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci fe->demodulator_priv = priv; 194862306a36Sopenharmony_ci pr_info("CXD2880 driver version: Ver %s\n", 194962306a36Sopenharmony_ci CXD2880_TNRDMD_DRIVER_VERSION); 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci return fe; 195262306a36Sopenharmony_ci} 195362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxd2880_attach); 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ciMODULE_DESCRIPTION("Sony CXD2880 DVB-T2/T tuner + demod driver"); 195662306a36Sopenharmony_ciMODULE_AUTHOR("Sony Semiconductor Solutions Corporation"); 195762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1958