19593810cSYasunari Takiguchi // SPDX-License-Identifier: GPL-2.0
29593810cSYasunari Takiguchi /*
39593810cSYasunari Takiguchi * cxd2880_top.c
49593810cSYasunari Takiguchi * Sony CXD2880 DVB-T2/T tuner + demodulator driver
59593810cSYasunari Takiguchi *
69593810cSYasunari Takiguchi * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
79593810cSYasunari Takiguchi */
89593810cSYasunari Takiguchi
99593810cSYasunari Takiguchi #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
109593810cSYasunari Takiguchi
119593810cSYasunari Takiguchi #include <linux/spi/spi.h>
129593810cSYasunari Takiguchi
137cbc3013SMauro Carvalho Chehab #include <media/dvb_frontend.h>
14f97fa3dcSAndy Shevchenko #include <linux/int_log.h>
159593810cSYasunari Takiguchi
169593810cSYasunari Takiguchi #include "cxd2880.h"
179593810cSYasunari Takiguchi #include "cxd2880_tnrdmd_mon.h"
189593810cSYasunari Takiguchi #include "cxd2880_tnrdmd_dvbt2_mon.h"
199593810cSYasunari Takiguchi #include "cxd2880_tnrdmd_dvbt_mon.h"
209593810cSYasunari Takiguchi #include "cxd2880_integ.h"
219593810cSYasunari Takiguchi #include "cxd2880_tnrdmd_dvbt2.h"
229593810cSYasunari Takiguchi #include "cxd2880_tnrdmd_dvbt.h"
239593810cSYasunari Takiguchi #include "cxd2880_devio_spi.h"
249593810cSYasunari Takiguchi #include "cxd2880_spi_device.h"
259593810cSYasunari Takiguchi #include "cxd2880_tnrdmd_driver_version.h"
269593810cSYasunari Takiguchi
279593810cSYasunari Takiguchi struct cxd2880_priv {
289593810cSYasunari Takiguchi struct cxd2880_tnrdmd tnrdmd;
299593810cSYasunari Takiguchi struct spi_device *spi;
309593810cSYasunari Takiguchi struct cxd2880_io regio;
319593810cSYasunari Takiguchi struct cxd2880_spi_device spi_device;
329593810cSYasunari Takiguchi struct cxd2880_spi cxd2880_spi;
339593810cSYasunari Takiguchi struct cxd2880_dvbt_tune_param dvbt_tune_param;
349593810cSYasunari Takiguchi struct cxd2880_dvbt2_tune_param dvbt2_tune_param;
359593810cSYasunari Takiguchi struct mutex *spi_mutex; /* For SPI access exclusive control */
369593810cSYasunari Takiguchi unsigned long pre_ber_update;
379593810cSYasunari Takiguchi unsigned long pre_ber_interval;
389593810cSYasunari Takiguchi unsigned long post_ber_update;
399593810cSYasunari Takiguchi unsigned long post_ber_interval;
409593810cSYasunari Takiguchi unsigned long ucblock_update;
419593810cSYasunari Takiguchi unsigned long ucblock_interval;
429593810cSYasunari Takiguchi enum fe_status s;
439593810cSYasunari Takiguchi };
449593810cSYasunari Takiguchi
cxd2880_pre_bit_err_t(struct cxd2880_tnrdmd * tnrdmd,u32 * pre_bit_err,u32 * pre_bit_count)459593810cSYasunari Takiguchi static int cxd2880_pre_bit_err_t(struct cxd2880_tnrdmd *tnrdmd,
469593810cSYasunari Takiguchi u32 *pre_bit_err, u32 *pre_bit_count)
479593810cSYasunari Takiguchi {
489593810cSYasunari Takiguchi u8 rdata[2];
499593810cSYasunari Takiguchi int ret;
509593810cSYasunari Takiguchi
519593810cSYasunari Takiguchi if (!tnrdmd || !pre_bit_err || !pre_bit_count)
529593810cSYasunari Takiguchi return -EINVAL;
539593810cSYasunari Takiguchi
549593810cSYasunari Takiguchi if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
559593810cSYasunari Takiguchi return -EINVAL;
569593810cSYasunari Takiguchi
579593810cSYasunari Takiguchi if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
589593810cSYasunari Takiguchi return -EINVAL;
599593810cSYasunari Takiguchi
609593810cSYasunari Takiguchi if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
619593810cSYasunari Takiguchi return -EINVAL;
629593810cSYasunari Takiguchi
639593810cSYasunari Takiguchi ret = slvt_freeze_reg(tnrdmd);
649593810cSYasunari Takiguchi if (ret)
659593810cSYasunari Takiguchi return ret;
669593810cSYasunari Takiguchi
679593810cSYasunari Takiguchi ret = tnrdmd->io->write_reg(tnrdmd->io,
689593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
699593810cSYasunari Takiguchi 0x00, 0x10);
709593810cSYasunari Takiguchi if (ret) {
719593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
729593810cSYasunari Takiguchi return ret;
739593810cSYasunari Takiguchi }
749593810cSYasunari Takiguchi
759593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
769593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
779593810cSYasunari Takiguchi 0x39, rdata, 1);
789593810cSYasunari Takiguchi if (ret) {
799593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
809593810cSYasunari Takiguchi return ret;
819593810cSYasunari Takiguchi }
829593810cSYasunari Takiguchi
839593810cSYasunari Takiguchi if ((rdata[0] & 0x01) == 0) {
849593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
859593810cSYasunari Takiguchi return -EAGAIN;
869593810cSYasunari Takiguchi }
879593810cSYasunari Takiguchi
889593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
899593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
909593810cSYasunari Takiguchi 0x22, rdata, 2);
919593810cSYasunari Takiguchi if (ret) {
929593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
939593810cSYasunari Takiguchi return ret;
949593810cSYasunari Takiguchi }
959593810cSYasunari Takiguchi
969593810cSYasunari Takiguchi *pre_bit_err = (rdata[0] << 8) | rdata[1];
979593810cSYasunari Takiguchi
989593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
999593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
1009593810cSYasunari Takiguchi 0x6f, rdata, 1);
1019593810cSYasunari Takiguchi if (ret) {
1029593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
1039593810cSYasunari Takiguchi return ret;
1049593810cSYasunari Takiguchi }
1059593810cSYasunari Takiguchi
1069593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
1079593810cSYasunari Takiguchi
1089593810cSYasunari Takiguchi *pre_bit_count = ((rdata[0] & 0x07) == 0) ?
1099593810cSYasunari Takiguchi 256 : (0x1000 << (rdata[0] & 0x07));
1109593810cSYasunari Takiguchi
1119593810cSYasunari Takiguchi return 0;
1129593810cSYasunari Takiguchi }
1139593810cSYasunari Takiguchi
cxd2880_pre_bit_err_t2(struct cxd2880_tnrdmd * tnrdmd,u32 * pre_bit_err,u32 * pre_bit_count)1149593810cSYasunari Takiguchi static int cxd2880_pre_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd,
1159593810cSYasunari Takiguchi u32 *pre_bit_err,
1169593810cSYasunari Takiguchi u32 *pre_bit_count)
1179593810cSYasunari Takiguchi {
1189593810cSYasunari Takiguchi u32 period_exp = 0;
1199593810cSYasunari Takiguchi u32 n_ldpc = 0;
1209593810cSYasunari Takiguchi u8 data[5];
1219593810cSYasunari Takiguchi int ret;
1229593810cSYasunari Takiguchi
1239593810cSYasunari Takiguchi if (!tnrdmd || !pre_bit_err || !pre_bit_count)
1249593810cSYasunari Takiguchi return -EINVAL;
1259593810cSYasunari Takiguchi
1269593810cSYasunari Takiguchi if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1279593810cSYasunari Takiguchi return -EINVAL;
1289593810cSYasunari Takiguchi
1299593810cSYasunari Takiguchi if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1309593810cSYasunari Takiguchi return -EINVAL;
1319593810cSYasunari Takiguchi
1329593810cSYasunari Takiguchi if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
1339593810cSYasunari Takiguchi return -EINVAL;
1349593810cSYasunari Takiguchi
1359593810cSYasunari Takiguchi ret = slvt_freeze_reg(tnrdmd);
1369593810cSYasunari Takiguchi if (ret)
1379593810cSYasunari Takiguchi return ret;
1389593810cSYasunari Takiguchi
1399593810cSYasunari Takiguchi ret = tnrdmd->io->write_reg(tnrdmd->io,
1409593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
1419593810cSYasunari Takiguchi 0x00, 0x0b);
1429593810cSYasunari Takiguchi if (ret) {
1439593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
1449593810cSYasunari Takiguchi return ret;
1459593810cSYasunari Takiguchi }
1469593810cSYasunari Takiguchi
1479593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
1489593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
1499593810cSYasunari Takiguchi 0x3c, data, sizeof(data));
1509593810cSYasunari Takiguchi if (ret) {
1519593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
1529593810cSYasunari Takiguchi return ret;
1539593810cSYasunari Takiguchi }
1549593810cSYasunari Takiguchi
1559593810cSYasunari Takiguchi if (!(data[0] & 0x01)) {
1569593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
1579593810cSYasunari Takiguchi return -EAGAIN;
1589593810cSYasunari Takiguchi }
1599593810cSYasunari Takiguchi *pre_bit_err =
1609593810cSYasunari Takiguchi ((data[1] & 0x0f) << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
1619593810cSYasunari Takiguchi
1629593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
1639593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
1649593810cSYasunari Takiguchi 0xa0, data, 1);
1659593810cSYasunari Takiguchi if (ret) {
1669593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
1679593810cSYasunari Takiguchi return ret;
1689593810cSYasunari Takiguchi }
1699593810cSYasunari Takiguchi
1709593810cSYasunari Takiguchi if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) ==
1719593810cSYasunari Takiguchi CXD2880_DVBT2_FEC_LDPC_16K)
1729593810cSYasunari Takiguchi n_ldpc = 16200;
1739593810cSYasunari Takiguchi else
1749593810cSYasunari Takiguchi n_ldpc = 64800;
1759593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
1769593810cSYasunari Takiguchi
1779593810cSYasunari Takiguchi ret = tnrdmd->io->write_reg(tnrdmd->io,
1789593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
1799593810cSYasunari Takiguchi 0x00, 0x20);
1809593810cSYasunari Takiguchi if (ret)
1819593810cSYasunari Takiguchi return ret;
1829593810cSYasunari Takiguchi
1839593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
1849593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
1859593810cSYasunari Takiguchi 0x6f, data, 1);
1869593810cSYasunari Takiguchi if (ret)
1879593810cSYasunari Takiguchi return ret;
1889593810cSYasunari Takiguchi
1899593810cSYasunari Takiguchi period_exp = data[0] & 0x0f;
1909593810cSYasunari Takiguchi
1919593810cSYasunari Takiguchi *pre_bit_count = (1U << period_exp) * n_ldpc;
1929593810cSYasunari Takiguchi
1939593810cSYasunari Takiguchi return 0;
1949593810cSYasunari Takiguchi }
1959593810cSYasunari Takiguchi
cxd2880_post_bit_err_t(struct cxd2880_tnrdmd * tnrdmd,u32 * post_bit_err,u32 * post_bit_count)1969593810cSYasunari Takiguchi static int cxd2880_post_bit_err_t(struct cxd2880_tnrdmd *tnrdmd,
1979593810cSYasunari Takiguchi u32 *post_bit_err,
1989593810cSYasunari Takiguchi u32 *post_bit_count)
1999593810cSYasunari Takiguchi {
2009593810cSYasunari Takiguchi u8 rdata[3];
2019593810cSYasunari Takiguchi u32 bit_error = 0;
2029593810cSYasunari Takiguchi u32 period_exp = 0;
2039593810cSYasunari Takiguchi int ret;
2049593810cSYasunari Takiguchi
2059593810cSYasunari Takiguchi if (!tnrdmd || !post_bit_err || !post_bit_count)
2069593810cSYasunari Takiguchi return -EINVAL;
2079593810cSYasunari Takiguchi
2089593810cSYasunari Takiguchi if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
2099593810cSYasunari Takiguchi return -EINVAL;
2109593810cSYasunari Takiguchi
2119593810cSYasunari Takiguchi if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
2129593810cSYasunari Takiguchi return -EINVAL;
2139593810cSYasunari Takiguchi
2149593810cSYasunari Takiguchi if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
2159593810cSYasunari Takiguchi return -EINVAL;
2169593810cSYasunari Takiguchi
2179593810cSYasunari Takiguchi ret = tnrdmd->io->write_reg(tnrdmd->io,
2189593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
2199593810cSYasunari Takiguchi 0x00, 0x0d);
2209593810cSYasunari Takiguchi if (ret)
2219593810cSYasunari Takiguchi return ret;
2229593810cSYasunari Takiguchi
2239593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
2249593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
2259593810cSYasunari Takiguchi 0x15, rdata, 3);
2269593810cSYasunari Takiguchi if (ret)
2279593810cSYasunari Takiguchi return ret;
2289593810cSYasunari Takiguchi
2299593810cSYasunari Takiguchi if ((rdata[0] & 0x40) == 0)
2309593810cSYasunari Takiguchi return -EAGAIN;
2319593810cSYasunari Takiguchi
2329593810cSYasunari Takiguchi *post_bit_err = ((rdata[0] & 0x3f) << 16) | (rdata[1] << 8) | rdata[2];
2339593810cSYasunari Takiguchi
2349593810cSYasunari Takiguchi ret = tnrdmd->io->write_reg(tnrdmd->io,
2359593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
2369593810cSYasunari Takiguchi 0x00, 0x10);
2379593810cSYasunari Takiguchi if (ret)
2389593810cSYasunari Takiguchi return ret;
2399593810cSYasunari Takiguchi
2409593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
2419593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
2429593810cSYasunari Takiguchi 0x60, rdata, 1);
2439593810cSYasunari Takiguchi if (ret)
2449593810cSYasunari Takiguchi return ret;
2459593810cSYasunari Takiguchi
2469593810cSYasunari Takiguchi period_exp = (rdata[0] & 0x1f);
2479593810cSYasunari Takiguchi
2489593810cSYasunari Takiguchi if (period_exp <= 11 && (bit_error > (1U << period_exp) * 204 * 8))
2499593810cSYasunari Takiguchi return -EAGAIN;
2509593810cSYasunari Takiguchi
2519593810cSYasunari Takiguchi *post_bit_count = (1U << period_exp) * 204 * 8;
2529593810cSYasunari Takiguchi
2539593810cSYasunari Takiguchi return 0;
2549593810cSYasunari Takiguchi }
2559593810cSYasunari Takiguchi
cxd2880_post_bit_err_t2(struct cxd2880_tnrdmd * tnrdmd,u32 * post_bit_err,u32 * post_bit_count)2569593810cSYasunari Takiguchi static int cxd2880_post_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd,
2579593810cSYasunari Takiguchi u32 *post_bit_err,
2589593810cSYasunari Takiguchi u32 *post_bit_count)
2599593810cSYasunari Takiguchi {
2609593810cSYasunari Takiguchi u32 period_exp = 0;
2619593810cSYasunari Takiguchi u32 n_bch = 0;
2629593810cSYasunari Takiguchi u8 data[3];
2639593810cSYasunari Takiguchi enum cxd2880_dvbt2_plp_fec plp_fec_type =
2649593810cSYasunari Takiguchi CXD2880_DVBT2_FEC_LDPC_16K;
2659593810cSYasunari Takiguchi enum cxd2880_dvbt2_plp_code_rate plp_code_rate =
2669593810cSYasunari Takiguchi CXD2880_DVBT2_R1_2;
2679593810cSYasunari Takiguchi int ret;
2689593810cSYasunari Takiguchi static const u16 n_bch_bits_lookup[2][8] = {
2699593810cSYasunari Takiguchi {7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480},
2709593810cSYasunari Takiguchi {32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920}
2719593810cSYasunari Takiguchi };
2729593810cSYasunari Takiguchi
2739593810cSYasunari Takiguchi if (!tnrdmd || !post_bit_err || !post_bit_count)
2749593810cSYasunari Takiguchi return -EINVAL;
2759593810cSYasunari Takiguchi
2769593810cSYasunari Takiguchi if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
2779593810cSYasunari Takiguchi return -EINVAL;
2789593810cSYasunari Takiguchi
2799593810cSYasunari Takiguchi if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
2809593810cSYasunari Takiguchi return -EINVAL;
2819593810cSYasunari Takiguchi
2829593810cSYasunari Takiguchi if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
2839593810cSYasunari Takiguchi return -EINVAL;
2849593810cSYasunari Takiguchi
2859593810cSYasunari Takiguchi ret = slvt_freeze_reg(tnrdmd);
2869593810cSYasunari Takiguchi if (ret)
2879593810cSYasunari Takiguchi return ret;
2889593810cSYasunari Takiguchi
2899593810cSYasunari Takiguchi ret = tnrdmd->io->write_reg(tnrdmd->io,
2909593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
2919593810cSYasunari Takiguchi 0x00, 0x0b);
2929593810cSYasunari Takiguchi if (ret) {
2939593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
2949593810cSYasunari Takiguchi return ret;
2959593810cSYasunari Takiguchi }
2969593810cSYasunari Takiguchi
2979593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
2989593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
2999593810cSYasunari Takiguchi 0x15, data, 3);
3009593810cSYasunari Takiguchi if (ret) {
3019593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
3029593810cSYasunari Takiguchi return ret;
3039593810cSYasunari Takiguchi }
3049593810cSYasunari Takiguchi
3059593810cSYasunari Takiguchi if (!(data[0] & 0x40)) {
3069593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
3079593810cSYasunari Takiguchi return -EAGAIN;
3089593810cSYasunari Takiguchi }
3099593810cSYasunari Takiguchi
3109593810cSYasunari Takiguchi *post_bit_err =
3119593810cSYasunari Takiguchi ((data[0] & 0x3f) << 16) | (data[1] << 8) | data[2];
3129593810cSYasunari Takiguchi
3139593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
3149593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
3159593810cSYasunari Takiguchi 0x9d, data, 1);
3169593810cSYasunari Takiguchi if (ret) {
3179593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
3189593810cSYasunari Takiguchi return ret;
3199593810cSYasunari Takiguchi }
3209593810cSYasunari Takiguchi
3219593810cSYasunari Takiguchi plp_code_rate =
3229593810cSYasunari Takiguchi (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07);
3239593810cSYasunari Takiguchi
3249593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
3259593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
3269593810cSYasunari Takiguchi 0xa0, data, 1);
3279593810cSYasunari Takiguchi if (ret) {
3289593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
3299593810cSYasunari Takiguchi return ret;
3309593810cSYasunari Takiguchi }
3319593810cSYasunari Takiguchi
3329593810cSYasunari Takiguchi plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03);
3339593810cSYasunari Takiguchi
3349593810cSYasunari Takiguchi slvt_unfreeze_reg(tnrdmd);
3359593810cSYasunari Takiguchi
3369593810cSYasunari Takiguchi ret = tnrdmd->io->write_reg(tnrdmd->io,
3379593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
3389593810cSYasunari Takiguchi 0x00, 0x20);
3399593810cSYasunari Takiguchi if (ret)
3409593810cSYasunari Takiguchi return ret;
3419593810cSYasunari Takiguchi
3429593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
3439593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
3449593810cSYasunari Takiguchi 0x72, data, 1);
3459593810cSYasunari Takiguchi if (ret)
3469593810cSYasunari Takiguchi return ret;
3479593810cSYasunari Takiguchi
3489593810cSYasunari Takiguchi period_exp = data[0] & 0x0f;
3499593810cSYasunari Takiguchi
3509593810cSYasunari Takiguchi if (plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K ||
3519593810cSYasunari Takiguchi plp_code_rate > CXD2880_DVBT2_R2_5)
3529593810cSYasunari Takiguchi return -EAGAIN;
3539593810cSYasunari Takiguchi
3549593810cSYasunari Takiguchi n_bch = n_bch_bits_lookup[plp_fec_type][plp_code_rate];
3559593810cSYasunari Takiguchi
3569593810cSYasunari Takiguchi if (*post_bit_err > ((1U << period_exp) * n_bch))
3579593810cSYasunari Takiguchi return -EAGAIN;
3589593810cSYasunari Takiguchi
3599593810cSYasunari Takiguchi *post_bit_count = (1U << period_exp) * n_bch;
3609593810cSYasunari Takiguchi
3619593810cSYasunari Takiguchi return 0;
3629593810cSYasunari Takiguchi }
3639593810cSYasunari Takiguchi
cxd2880_read_block_err_t(struct cxd2880_tnrdmd * tnrdmd,u32 * block_err,u32 * block_count)3649593810cSYasunari Takiguchi static int cxd2880_read_block_err_t(struct cxd2880_tnrdmd *tnrdmd,
3659593810cSYasunari Takiguchi u32 *block_err,
3669593810cSYasunari Takiguchi u32 *block_count)
3679593810cSYasunari Takiguchi {
3689593810cSYasunari Takiguchi u8 rdata[3];
3699593810cSYasunari Takiguchi int ret;
3709593810cSYasunari Takiguchi
3719593810cSYasunari Takiguchi if (!tnrdmd || !block_err || !block_count)
3729593810cSYasunari Takiguchi return -EINVAL;
3739593810cSYasunari Takiguchi
3749593810cSYasunari Takiguchi if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
3759593810cSYasunari Takiguchi return -EINVAL;
3769593810cSYasunari Takiguchi
3779593810cSYasunari Takiguchi if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
3789593810cSYasunari Takiguchi return -EINVAL;
3799593810cSYasunari Takiguchi
3809593810cSYasunari Takiguchi if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
3819593810cSYasunari Takiguchi return -EINVAL;
3829593810cSYasunari Takiguchi
3839593810cSYasunari Takiguchi ret = tnrdmd->io->write_reg(tnrdmd->io,
3849593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
3859593810cSYasunari Takiguchi 0x00, 0x0d);
3869593810cSYasunari Takiguchi if (ret)
3879593810cSYasunari Takiguchi return ret;
3889593810cSYasunari Takiguchi
3899593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
3909593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
3919593810cSYasunari Takiguchi 0x18, rdata, 3);
3929593810cSYasunari Takiguchi if (ret)
3939593810cSYasunari Takiguchi return ret;
3949593810cSYasunari Takiguchi
3959593810cSYasunari Takiguchi if ((rdata[0] & 0x01) == 0)
3969593810cSYasunari Takiguchi return -EAGAIN;
3979593810cSYasunari Takiguchi
3989593810cSYasunari Takiguchi *block_err = (rdata[1] << 8) | rdata[2];
3999593810cSYasunari Takiguchi
4009593810cSYasunari Takiguchi ret = tnrdmd->io->write_reg(tnrdmd->io,
4019593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
4029593810cSYasunari Takiguchi 0x00, 0x10);
4039593810cSYasunari Takiguchi if (ret)
4049593810cSYasunari Takiguchi return ret;
4059593810cSYasunari Takiguchi
4069593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
4079593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
4089593810cSYasunari Takiguchi 0x5c, rdata, 1);
4099593810cSYasunari Takiguchi if (ret)
4109593810cSYasunari Takiguchi return ret;
4119593810cSYasunari Takiguchi
4129593810cSYasunari Takiguchi *block_count = 1U << (rdata[0] & 0x0f);
4139593810cSYasunari Takiguchi
4149593810cSYasunari Takiguchi if ((*block_count == 0) || (*block_err > *block_count))
4159593810cSYasunari Takiguchi return -EAGAIN;
4169593810cSYasunari Takiguchi
4179593810cSYasunari Takiguchi return 0;
4189593810cSYasunari Takiguchi }
4199593810cSYasunari Takiguchi
cxd2880_read_block_err_t2(struct cxd2880_tnrdmd * tnrdmd,u32 * block_err,u32 * block_count)4209593810cSYasunari Takiguchi static int cxd2880_read_block_err_t2(struct cxd2880_tnrdmd *tnrdmd,
4219593810cSYasunari Takiguchi u32 *block_err,
4229593810cSYasunari Takiguchi u32 *block_count)
4239593810cSYasunari Takiguchi {
4249593810cSYasunari Takiguchi u8 rdata[3];
4259593810cSYasunari Takiguchi int ret;
4269593810cSYasunari Takiguchi
4279593810cSYasunari Takiguchi if (!tnrdmd || !block_err || !block_count)
4289593810cSYasunari Takiguchi return -EINVAL;
4299593810cSYasunari Takiguchi
4309593810cSYasunari Takiguchi if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
4319593810cSYasunari Takiguchi return -EINVAL;
4329593810cSYasunari Takiguchi
4339593810cSYasunari Takiguchi if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
4349593810cSYasunari Takiguchi return -EINVAL;
4359593810cSYasunari Takiguchi if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
4369593810cSYasunari Takiguchi return -EINVAL;
4379593810cSYasunari Takiguchi
4389593810cSYasunari Takiguchi ret = tnrdmd->io->write_reg(tnrdmd->io,
4399593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
4409593810cSYasunari Takiguchi 0x00, 0x0b);
4419593810cSYasunari Takiguchi if (ret)
4429593810cSYasunari Takiguchi return ret;
4439593810cSYasunari Takiguchi
4449593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
4459593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
4469593810cSYasunari Takiguchi 0x18, rdata, 3);
4479593810cSYasunari Takiguchi if (ret)
4489593810cSYasunari Takiguchi return ret;
4499593810cSYasunari Takiguchi
4509593810cSYasunari Takiguchi if ((rdata[0] & 0x01) == 0)
4519593810cSYasunari Takiguchi return -EAGAIN;
4529593810cSYasunari Takiguchi
4539593810cSYasunari Takiguchi *block_err = (rdata[1] << 8) | rdata[2];
4549593810cSYasunari Takiguchi
4559593810cSYasunari Takiguchi ret = tnrdmd->io->write_reg(tnrdmd->io,
4569593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
4579593810cSYasunari Takiguchi 0x00, 0x24);
4589593810cSYasunari Takiguchi if (ret)
4599593810cSYasunari Takiguchi return ret;
4609593810cSYasunari Takiguchi
4619593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
4629593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
4639593810cSYasunari Takiguchi 0xdc, rdata, 1);
4649593810cSYasunari Takiguchi if (ret)
4659593810cSYasunari Takiguchi return ret;
4669593810cSYasunari Takiguchi
4679593810cSYasunari Takiguchi *block_count = 1U << (rdata[0] & 0x0f);
4689593810cSYasunari Takiguchi
4699593810cSYasunari Takiguchi if ((*block_count == 0) || (*block_err > *block_count))
4709593810cSYasunari Takiguchi return -EAGAIN;
4719593810cSYasunari Takiguchi
4729593810cSYasunari Takiguchi return 0;
4739593810cSYasunari Takiguchi }
4749593810cSYasunari Takiguchi
cxd2880_release(struct dvb_frontend * fe)4759593810cSYasunari Takiguchi static void cxd2880_release(struct dvb_frontend *fe)
4769593810cSYasunari Takiguchi {
4779593810cSYasunari Takiguchi struct cxd2880_priv *priv = NULL;
4789593810cSYasunari Takiguchi
4799593810cSYasunari Takiguchi if (!fe) {
4809593810cSYasunari Takiguchi pr_err("invalid arg.\n");
4819593810cSYasunari Takiguchi return;
4829593810cSYasunari Takiguchi }
4839593810cSYasunari Takiguchi priv = fe->demodulator_priv;
4849593810cSYasunari Takiguchi kfree(priv);
4859593810cSYasunari Takiguchi }
4869593810cSYasunari Takiguchi
cxd2880_init(struct dvb_frontend * fe)4879593810cSYasunari Takiguchi static int cxd2880_init(struct dvb_frontend *fe)
4889593810cSYasunari Takiguchi {
4899593810cSYasunari Takiguchi int ret;
4909593810cSYasunari Takiguchi struct cxd2880_priv *priv = NULL;
4919593810cSYasunari Takiguchi struct cxd2880_tnrdmd_create_param create_param;
4929593810cSYasunari Takiguchi
4939593810cSYasunari Takiguchi if (!fe) {
4949593810cSYasunari Takiguchi pr_err("invalid arg.\n");
4959593810cSYasunari Takiguchi return -EINVAL;
4969593810cSYasunari Takiguchi }
4979593810cSYasunari Takiguchi
4989593810cSYasunari Takiguchi priv = fe->demodulator_priv;
4999593810cSYasunari Takiguchi
5009593810cSYasunari Takiguchi create_param.ts_output_if = CXD2880_TNRDMD_TSOUT_IF_SPI;
5019593810cSYasunari Takiguchi create_param.xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_NONE;
5029593810cSYasunari Takiguchi create_param.en_internal_ldo = 1;
5039593810cSYasunari Takiguchi create_param.xosc_cap = 18;
5049593810cSYasunari Takiguchi create_param.xosc_i = 8;
5059593810cSYasunari Takiguchi create_param.stationary_use = 1;
5069593810cSYasunari Takiguchi
5079593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
5089593810cSYasunari Takiguchi if (priv->tnrdmd.io != &priv->regio) {
5099593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_create(&priv->tnrdmd,
5109593810cSYasunari Takiguchi &priv->regio, &create_param);
5119593810cSYasunari Takiguchi if (ret) {
5129593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
5139593810cSYasunari Takiguchi pr_info("cxd2880 tnrdmd create failed %d\n", ret);
5149593810cSYasunari Takiguchi return ret;
5159593810cSYasunari Takiguchi }
5169593810cSYasunari Takiguchi }
5179593810cSYasunari Takiguchi ret = cxd2880_integ_init(&priv->tnrdmd);
5189593810cSYasunari Takiguchi if (ret) {
5199593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
5209593810cSYasunari Takiguchi pr_err("cxd2880 integ init failed %d\n", ret);
5219593810cSYasunari Takiguchi return ret;
5229593810cSYasunari Takiguchi }
523f2e7af0bSYasunari Takiguchi
524f2e7af0bSYasunari Takiguchi ret = cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
525f2e7af0bSYasunari Takiguchi CXD2880_TNRDMD_CFG_TSPIN_CURRENT,
526f2e7af0bSYasunari Takiguchi 0x00);
527f2e7af0bSYasunari Takiguchi if (ret) {
528f2e7af0bSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
529f2e7af0bSYasunari Takiguchi pr_err("cxd2880 set config failed %d\n", ret);
530f2e7af0bSYasunari Takiguchi return ret;
531f2e7af0bSYasunari Takiguchi }
5329593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
5339593810cSYasunari Takiguchi
5349593810cSYasunari Takiguchi pr_debug("OK.\n");
5359593810cSYasunari Takiguchi
5369593810cSYasunari Takiguchi return ret;
5379593810cSYasunari Takiguchi }
5389593810cSYasunari Takiguchi
cxd2880_sleep(struct dvb_frontend * fe)5399593810cSYasunari Takiguchi static int cxd2880_sleep(struct dvb_frontend *fe)
5409593810cSYasunari Takiguchi {
5419593810cSYasunari Takiguchi int ret;
5429593810cSYasunari Takiguchi struct cxd2880_priv *priv = NULL;
5439593810cSYasunari Takiguchi
5449593810cSYasunari Takiguchi if (!fe) {
5459593810cSYasunari Takiguchi pr_err("invalid arg\n");
5469593810cSYasunari Takiguchi return -EINVAL;
5479593810cSYasunari Takiguchi }
5489593810cSYasunari Takiguchi
5499593810cSYasunari Takiguchi priv = fe->demodulator_priv;
5509593810cSYasunari Takiguchi
5519593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
5529593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_sleep(&priv->tnrdmd);
5539593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
5549593810cSYasunari Takiguchi
5559593810cSYasunari Takiguchi pr_debug("tnrdmd_sleep ret %d\n", ret);
5569593810cSYasunari Takiguchi
5579593810cSYasunari Takiguchi return ret;
5589593810cSYasunari Takiguchi }
5599593810cSYasunari Takiguchi
cxd2880_read_signal_strength(struct dvb_frontend * fe,u16 * strength)5609593810cSYasunari Takiguchi static int cxd2880_read_signal_strength(struct dvb_frontend *fe,
5619593810cSYasunari Takiguchi u16 *strength)
5629593810cSYasunari Takiguchi {
5639593810cSYasunari Takiguchi int ret;
5649593810cSYasunari Takiguchi struct cxd2880_priv *priv = NULL;
5659593810cSYasunari Takiguchi struct dtv_frontend_properties *c = NULL;
5669593810cSYasunari Takiguchi int level = 0;
5679593810cSYasunari Takiguchi
5689593810cSYasunari Takiguchi if (!fe || !strength) {
5699593810cSYasunari Takiguchi pr_err("invalid arg\n");
5709593810cSYasunari Takiguchi return -EINVAL;
5719593810cSYasunari Takiguchi }
5729593810cSYasunari Takiguchi
5739593810cSYasunari Takiguchi priv = fe->demodulator_priv;
5749593810cSYasunari Takiguchi c = &fe->dtv_property_cache;
5759593810cSYasunari Takiguchi
5769593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
5779593810cSYasunari Takiguchi if (c->delivery_system == SYS_DVBT ||
5789593810cSYasunari Takiguchi c->delivery_system == SYS_DVBT2) {
5799593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &level);
5809593810cSYasunari Takiguchi } else {
5819593810cSYasunari Takiguchi pr_debug("invalid system\n");
5829593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
5839593810cSYasunari Takiguchi return -EINVAL;
5849593810cSYasunari Takiguchi }
5859593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
5869593810cSYasunari Takiguchi
5879593810cSYasunari Takiguchi level /= 125;
5889593810cSYasunari Takiguchi /*
5899593810cSYasunari Takiguchi * level should be between -105dBm and -30dBm.
5909593810cSYasunari Takiguchi * E.g. they should be between:
5919593810cSYasunari Takiguchi * -105000/125 = -840 and -30000/125 = -240
5929593810cSYasunari Takiguchi */
5939593810cSYasunari Takiguchi level = clamp(level, -840, -240);
5949593810cSYasunari Takiguchi /* scale value to 0x0000-0xffff */
5959593810cSYasunari Takiguchi *strength = ((level + 840) * 0xffff) / (-240 + 840);
5969593810cSYasunari Takiguchi
5979593810cSYasunari Takiguchi if (ret)
5989593810cSYasunari Takiguchi pr_debug("ret = %d\n", ret);
5999593810cSYasunari Takiguchi
6009593810cSYasunari Takiguchi return ret;
6019593810cSYasunari Takiguchi }
6029593810cSYasunari Takiguchi
cxd2880_read_snr(struct dvb_frontend * fe,u16 * snr)6039593810cSYasunari Takiguchi static int cxd2880_read_snr(struct dvb_frontend *fe, u16 *snr)
6049593810cSYasunari Takiguchi {
6059593810cSYasunari Takiguchi int ret;
6069593810cSYasunari Takiguchi int snrvalue = 0;
6079593810cSYasunari Takiguchi struct cxd2880_priv *priv = NULL;
6089593810cSYasunari Takiguchi struct dtv_frontend_properties *c = NULL;
6099593810cSYasunari Takiguchi
6109593810cSYasunari Takiguchi if (!fe || !snr) {
6119593810cSYasunari Takiguchi pr_err("invalid arg\n");
6129593810cSYasunari Takiguchi return -EINVAL;
6139593810cSYasunari Takiguchi }
6149593810cSYasunari Takiguchi
6159593810cSYasunari Takiguchi priv = fe->demodulator_priv;
6169593810cSYasunari Takiguchi c = &fe->dtv_property_cache;
6179593810cSYasunari Takiguchi
6189593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
6199593810cSYasunari Takiguchi if (c->delivery_system == SYS_DVBT) {
6209593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt_mon_snr(&priv->tnrdmd,
6219593810cSYasunari Takiguchi &snrvalue);
6229593810cSYasunari Takiguchi } else if (c->delivery_system == SYS_DVBT2) {
6239593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt2_mon_snr(&priv->tnrdmd,
6249593810cSYasunari Takiguchi &snrvalue);
6259593810cSYasunari Takiguchi } else {
6269593810cSYasunari Takiguchi pr_err("invalid system\n");
6279593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
6289593810cSYasunari Takiguchi return -EINVAL;
6299593810cSYasunari Takiguchi }
6309593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
6319593810cSYasunari Takiguchi
6329593810cSYasunari Takiguchi if (snrvalue < 0)
6339593810cSYasunari Takiguchi snrvalue = 0;
6349593810cSYasunari Takiguchi *snr = snrvalue;
6359593810cSYasunari Takiguchi
6369593810cSYasunari Takiguchi if (ret)
6379593810cSYasunari Takiguchi pr_debug("ret = %d\n", ret);
6389593810cSYasunari Takiguchi
6399593810cSYasunari Takiguchi return ret;
6409593810cSYasunari Takiguchi }
6419593810cSYasunari Takiguchi
cxd2880_read_ucblocks(struct dvb_frontend * fe,u32 * ucblocks)6429593810cSYasunari Takiguchi static int cxd2880_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
6439593810cSYasunari Takiguchi {
6449593810cSYasunari Takiguchi int ret;
6459593810cSYasunari Takiguchi struct cxd2880_priv *priv = NULL;
6469593810cSYasunari Takiguchi struct dtv_frontend_properties *c = NULL;
6479593810cSYasunari Takiguchi
6489593810cSYasunari Takiguchi if (!fe || !ucblocks) {
6499593810cSYasunari Takiguchi pr_err("invalid arg\n");
6509593810cSYasunari Takiguchi return -EINVAL;
6519593810cSYasunari Takiguchi }
6529593810cSYasunari Takiguchi
6539593810cSYasunari Takiguchi priv = fe->demodulator_priv;
6549593810cSYasunari Takiguchi c = &fe->dtv_property_cache;
6559593810cSYasunari Takiguchi
6569593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
6579593810cSYasunari Takiguchi if (c->delivery_system == SYS_DVBT) {
6589593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt_mon_packet_error_number(&priv->tnrdmd,
6599593810cSYasunari Takiguchi ucblocks);
6609593810cSYasunari Takiguchi } else if (c->delivery_system == SYS_DVBT2) {
6619593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt2_mon_packet_error_number(&priv->tnrdmd,
6629593810cSYasunari Takiguchi ucblocks);
6639593810cSYasunari Takiguchi } else {
6649593810cSYasunari Takiguchi pr_err("invalid system\n");
6659593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
6669593810cSYasunari Takiguchi return -EINVAL;
6679593810cSYasunari Takiguchi }
6689593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
6699593810cSYasunari Takiguchi
6709593810cSYasunari Takiguchi if (ret)
6719593810cSYasunari Takiguchi pr_debug("ret = %d\n", ret);
6729593810cSYasunari Takiguchi
6739593810cSYasunari Takiguchi return ret;
6749593810cSYasunari Takiguchi }
6759593810cSYasunari Takiguchi
cxd2880_read_ber(struct dvb_frontend * fe,u32 * ber)6769593810cSYasunari Takiguchi static int cxd2880_read_ber(struct dvb_frontend *fe, u32 *ber)
6779593810cSYasunari Takiguchi {
6789593810cSYasunari Takiguchi *ber = 0;
6799593810cSYasunari Takiguchi
6809593810cSYasunari Takiguchi return 0;
6819593810cSYasunari Takiguchi }
6829593810cSYasunari Takiguchi
cxd2880_set_ber_per_period_t(struct dvb_frontend * fe)6839593810cSYasunari Takiguchi static int cxd2880_set_ber_per_period_t(struct dvb_frontend *fe)
6849593810cSYasunari Takiguchi {
6859593810cSYasunari Takiguchi int ret;
6869593810cSYasunari Takiguchi struct cxd2880_priv *priv;
6879593810cSYasunari Takiguchi struct cxd2880_dvbt_tpsinfo info;
6881bcecaceSColin Ian King enum cxd2880_dtv_bandwidth bw;
6899593810cSYasunari Takiguchi u32 pre_ber_rate = 0;
6909593810cSYasunari Takiguchi u32 post_ber_rate = 0;
6919593810cSYasunari Takiguchi u32 ucblock_rate = 0;
6929593810cSYasunari Takiguchi u32 mes_exp = 0;
6939593810cSYasunari Takiguchi static const int cr_table[5] = {31500, 42000, 47250, 52500, 55125};
6949593810cSYasunari Takiguchi static const int denominator_tbl[4] = {125664, 129472, 137088, 152320};
6959593810cSYasunari Takiguchi
6969593810cSYasunari Takiguchi if (!fe) {
6979593810cSYasunari Takiguchi pr_err("invalid arg\n");
6989593810cSYasunari Takiguchi return -EINVAL;
6999593810cSYasunari Takiguchi }
7009593810cSYasunari Takiguchi
7019593810cSYasunari Takiguchi priv = fe->demodulator_priv;
7029593810cSYasunari Takiguchi bw = priv->dvbt_tune_param.bandwidth;
7039593810cSYasunari Takiguchi
7049593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd,
7059593810cSYasunari Takiguchi &info);
7069593810cSYasunari Takiguchi if (ret) {
7079593810cSYasunari Takiguchi pr_err("tps monitor error ret = %d\n", ret);
7089593810cSYasunari Takiguchi info.hierarchy = CXD2880_DVBT_HIERARCHY_NON;
7099593810cSYasunari Takiguchi info.constellation = CXD2880_DVBT_CONSTELLATION_QPSK;
7109593810cSYasunari Takiguchi info.guard = CXD2880_DVBT_GUARD_1_4;
7119593810cSYasunari Takiguchi info.rate_hp = CXD2880_DVBT_CODERATE_1_2;
7129593810cSYasunari Takiguchi info.rate_lp = CXD2880_DVBT_CODERATE_1_2;
7139593810cSYasunari Takiguchi }
7149593810cSYasunari Takiguchi
7159593810cSYasunari Takiguchi if (info.hierarchy == CXD2880_DVBT_HIERARCHY_NON) {
7169593810cSYasunari Takiguchi pre_ber_rate = 63000000 * bw * (info.constellation * 2 + 2) /
7179593810cSYasunari Takiguchi denominator_tbl[info.guard];
7189593810cSYasunari Takiguchi
7199593810cSYasunari Takiguchi post_ber_rate = 1000 * cr_table[info.rate_hp] * bw *
7209593810cSYasunari Takiguchi (info.constellation * 2 + 2) /
7219593810cSYasunari Takiguchi denominator_tbl[info.guard];
7229593810cSYasunari Takiguchi
7239593810cSYasunari Takiguchi ucblock_rate = 875 * cr_table[info.rate_hp] * bw *
7249593810cSYasunari Takiguchi (info.constellation * 2 + 2) /
7259593810cSYasunari Takiguchi denominator_tbl[info.guard];
7269593810cSYasunari Takiguchi } else {
7279593810cSYasunari Takiguchi u8 data = 0;
7289593810cSYasunari Takiguchi struct cxd2880_tnrdmd *tnrdmd = &priv->tnrdmd;
7299593810cSYasunari Takiguchi
7309593810cSYasunari Takiguchi ret = tnrdmd->io->write_reg(tnrdmd->io,
7319593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
7329593810cSYasunari Takiguchi 0x00, 0x10);
7339593810cSYasunari Takiguchi if (!ret) {
7349593810cSYasunari Takiguchi ret = tnrdmd->io->read_regs(tnrdmd->io,
7359593810cSYasunari Takiguchi CXD2880_IO_TGT_DMD,
7369593810cSYasunari Takiguchi 0x67, &data, 1);
7379593810cSYasunari Takiguchi if (ret)
7389593810cSYasunari Takiguchi data = 0x00;
7399593810cSYasunari Takiguchi } else {
7409593810cSYasunari Takiguchi data = 0x00;
7419593810cSYasunari Takiguchi }
7429593810cSYasunari Takiguchi
7439593810cSYasunari Takiguchi if (data & 0x01) { /* Low priority */
7449593810cSYasunari Takiguchi pre_ber_rate =
7459593810cSYasunari Takiguchi 63000000 * bw * (info.constellation * 2 + 2) /
7469593810cSYasunari Takiguchi denominator_tbl[info.guard];
7479593810cSYasunari Takiguchi
7489593810cSYasunari Takiguchi post_ber_rate = 1000 * cr_table[info.rate_lp] * bw *
7499593810cSYasunari Takiguchi (info.constellation * 2 + 2) /
7509593810cSYasunari Takiguchi denominator_tbl[info.guard];
7519593810cSYasunari Takiguchi
7529593810cSYasunari Takiguchi ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_lp] *
7539593810cSYasunari Takiguchi bw * (info.constellation * 2 + 2) /
7549593810cSYasunari Takiguchi denominator_tbl[info.guard];
7559593810cSYasunari Takiguchi } else { /* High priority */
7569593810cSYasunari Takiguchi pre_ber_rate =
7579593810cSYasunari Takiguchi 63000000 * bw * 2 / denominator_tbl[info.guard];
7589593810cSYasunari Takiguchi
7599593810cSYasunari Takiguchi post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * 2 /
7609593810cSYasunari Takiguchi denominator_tbl[info.guard];
7619593810cSYasunari Takiguchi
7629593810cSYasunari Takiguchi ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_hp] *
7639593810cSYasunari Takiguchi bw * 2 / denominator_tbl[info.guard];
7649593810cSYasunari Takiguchi }
7659593810cSYasunari Takiguchi }
7669593810cSYasunari Takiguchi
7679593810cSYasunari Takiguchi mes_exp = pre_ber_rate < 8192 ? 8 : intlog2(pre_ber_rate) >> 24;
7689593810cSYasunari Takiguchi priv->pre_ber_interval =
7699593810cSYasunari Takiguchi ((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) /
7709593810cSYasunari Takiguchi pre_ber_rate;
7719593810cSYasunari Takiguchi cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
7729593810cSYasunari Takiguchi CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD,
7739593810cSYasunari Takiguchi mes_exp == 8 ? 0 : mes_exp - 12);
7749593810cSYasunari Takiguchi
7759593810cSYasunari Takiguchi mes_exp = intlog2(post_ber_rate) >> 24;
7769593810cSYasunari Takiguchi priv->post_ber_interval =
7779593810cSYasunari Takiguchi ((1U << mes_exp) * 1000 + (post_ber_rate / 2)) /
7789593810cSYasunari Takiguchi post_ber_rate;
7799593810cSYasunari Takiguchi cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
7809593810cSYasunari Takiguchi CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD,
7819593810cSYasunari Takiguchi mes_exp);
7829593810cSYasunari Takiguchi
7839593810cSYasunari Takiguchi mes_exp = intlog2(ucblock_rate) >> 24;
7849593810cSYasunari Takiguchi priv->ucblock_interval =
7859593810cSYasunari Takiguchi ((1U << mes_exp) * 1000 + (ucblock_rate / 2)) /
7869593810cSYasunari Takiguchi ucblock_rate;
7879593810cSYasunari Takiguchi cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
7889593810cSYasunari Takiguchi CXD2880_TNRDMD_CFG_DVBT_PER_MES,
7899593810cSYasunari Takiguchi mes_exp);
7909593810cSYasunari Takiguchi
7919593810cSYasunari Takiguchi return 0;
7929593810cSYasunari Takiguchi }
7939593810cSYasunari Takiguchi
cxd2880_set_ber_per_period_t2(struct dvb_frontend * fe)7949593810cSYasunari Takiguchi static int cxd2880_set_ber_per_period_t2(struct dvb_frontend *fe)
7959593810cSYasunari Takiguchi {
7969593810cSYasunari Takiguchi int ret;
7979593810cSYasunari Takiguchi struct cxd2880_priv *priv;
7989593810cSYasunari Takiguchi struct cxd2880_dvbt2_l1pre l1pre;
7999593810cSYasunari Takiguchi struct cxd2880_dvbt2_l1post l1post;
8009593810cSYasunari Takiguchi struct cxd2880_dvbt2_plp plp;
8019593810cSYasunari Takiguchi struct cxd2880_dvbt2_bbheader bbheader;
8029593810cSYasunari Takiguchi enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
8039593810cSYasunari Takiguchi u32 pre_ber_rate = 0;
8049593810cSYasunari Takiguchi u32 post_ber_rate = 0;
8059593810cSYasunari Takiguchi u32 ucblock_rate = 0;
8069593810cSYasunari Takiguchi u32 mes_exp = 0;
8079593810cSYasunari Takiguchi u32 term_a = 0;
8089593810cSYasunari Takiguchi u32 term_b = 0;
8099593810cSYasunari Takiguchi u32 denominator = 0;
8109593810cSYasunari Takiguchi static const u32 gi_tbl[7] = {32, 64, 128, 256, 8, 152, 76};
8119593810cSYasunari Takiguchi static const u8 n_tbl[6] = {8, 2, 4, 16, 1, 1};
8129593810cSYasunari Takiguchi static const u8 mode_tbl[6] = {2, 8, 4, 1, 16, 32};
8139593810cSYasunari Takiguchi static const u32 kbch_tbl[2][8] = {
8149593810cSYasunari Takiguchi {6952, 9472, 10552, 11632, 12352, 13072, 5152, 6232},
8159593810cSYasunari Takiguchi {32128, 38608, 42960, 48328, 51568, 53760, 0, 0}
8169593810cSYasunari Takiguchi };
8179593810cSYasunari Takiguchi
8189593810cSYasunari Takiguchi if (!fe) {
8199593810cSYasunari Takiguchi pr_err("invalid arg\n");
8209593810cSYasunari Takiguchi return -EINVAL;
8219593810cSYasunari Takiguchi }
8229593810cSYasunari Takiguchi
8239593810cSYasunari Takiguchi priv = fe->demodulator_priv;
8249593810cSYasunari Takiguchi bw = priv->dvbt2_tune_param.bandwidth;
8259593810cSYasunari Takiguchi
8269593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre);
8279593810cSYasunari Takiguchi if (ret) {
8289593810cSYasunari Takiguchi pr_info("l1 pre error\n");
8299593810cSYasunari Takiguchi goto error_ber_setting;
8309593810cSYasunari Takiguchi }
8319593810cSYasunari Takiguchi
8329593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt2_mon_active_plp(&priv->tnrdmd,
8339593810cSYasunari Takiguchi CXD2880_DVBT2_PLP_DATA, &plp);
8349593810cSYasunari Takiguchi if (ret) {
8359593810cSYasunari Takiguchi pr_info("plp info error\n");
8369593810cSYasunari Takiguchi goto error_ber_setting;
8379593810cSYasunari Takiguchi }
8389593810cSYasunari Takiguchi
8399593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt2_mon_l1_post(&priv->tnrdmd, &l1post);
8409593810cSYasunari Takiguchi if (ret) {
8419593810cSYasunari Takiguchi pr_info("l1 post error\n");
8429593810cSYasunari Takiguchi goto error_ber_setting;
8439593810cSYasunari Takiguchi }
8449593810cSYasunari Takiguchi
8459593810cSYasunari Takiguchi term_a =
8469593810cSYasunari Takiguchi (mode_tbl[l1pre.fft_mode] * (1024 + gi_tbl[l1pre.gi])) *
8479593810cSYasunari Takiguchi (l1pre.num_symbols + n_tbl[l1pre.fft_mode]) + 2048;
8489593810cSYasunari Takiguchi
8499593810cSYasunari Takiguchi if (l1pre.mixed && l1post.fef_intvl) {
8509593810cSYasunari Takiguchi term_b = (l1post.fef_length + (l1post.fef_intvl / 2)) /
8519593810cSYasunari Takiguchi l1post.fef_intvl;
8529593810cSYasunari Takiguchi } else {
8539593810cSYasunari Takiguchi term_b = 0;
8549593810cSYasunari Takiguchi }
8559593810cSYasunari Takiguchi
8569593810cSYasunari Takiguchi switch (bw) {
8579593810cSYasunari Takiguchi case CXD2880_DTV_BW_1_7_MHZ:
8589593810cSYasunari Takiguchi denominator = ((term_a + term_b) * 71 + (131 / 2)) / 131;
8599593810cSYasunari Takiguchi break;
8609593810cSYasunari Takiguchi case CXD2880_DTV_BW_5_MHZ:
8619593810cSYasunari Takiguchi denominator = ((term_a + term_b) * 7 + 20) / 40;
8629593810cSYasunari Takiguchi break;
8639593810cSYasunari Takiguchi case CXD2880_DTV_BW_6_MHZ:
8649593810cSYasunari Takiguchi denominator = ((term_a + term_b) * 7 + 24) / 48;
8659593810cSYasunari Takiguchi break;
8669593810cSYasunari Takiguchi case CXD2880_DTV_BW_7_MHZ:
8679593810cSYasunari Takiguchi denominator = ((term_a + term_b) + 4) / 8;
8689593810cSYasunari Takiguchi break;
8699593810cSYasunari Takiguchi case CXD2880_DTV_BW_8_MHZ:
8709593810cSYasunari Takiguchi default:
8719593810cSYasunari Takiguchi denominator = ((term_a + term_b) * 7 + 32) / 64;
8729593810cSYasunari Takiguchi break;
8739593810cSYasunari Takiguchi }
8749593810cSYasunari Takiguchi
8759593810cSYasunari Takiguchi if (plp.til_type && plp.til_len) {
8769593810cSYasunari Takiguchi pre_ber_rate =
8779593810cSYasunari Takiguchi (plp.num_blocks_max * 1000000 + (denominator / 2)) /
8789593810cSYasunari Takiguchi denominator;
8799593810cSYasunari Takiguchi pre_ber_rate = (pre_ber_rate + (plp.til_len / 2)) /
8809593810cSYasunari Takiguchi plp.til_len;
8819593810cSYasunari Takiguchi } else {
8829593810cSYasunari Takiguchi pre_ber_rate =
8839593810cSYasunari Takiguchi (plp.num_blocks_max * 1000000 + (denominator / 2)) /
8849593810cSYasunari Takiguchi denominator;
8859593810cSYasunari Takiguchi }
8869593810cSYasunari Takiguchi
8879593810cSYasunari Takiguchi post_ber_rate = pre_ber_rate;
8889593810cSYasunari Takiguchi
8899593810cSYasunari Takiguchi mes_exp = intlog2(pre_ber_rate) >> 24;
8909593810cSYasunari Takiguchi priv->pre_ber_interval =
8919593810cSYasunari Takiguchi ((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) /
8929593810cSYasunari Takiguchi pre_ber_rate;
8939593810cSYasunari Takiguchi cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
8949593810cSYasunari Takiguchi CXD2880_TNRDMD_CFG_DVBT2_LBER_MES,
8959593810cSYasunari Takiguchi mes_exp);
8969593810cSYasunari Takiguchi
8979593810cSYasunari Takiguchi mes_exp = intlog2(post_ber_rate) >> 24;
8989593810cSYasunari Takiguchi priv->post_ber_interval =
8999593810cSYasunari Takiguchi ((1U << mes_exp) * 1000 + (post_ber_rate / 2)) /
9009593810cSYasunari Takiguchi post_ber_rate;
9019593810cSYasunari Takiguchi cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
9029593810cSYasunari Takiguchi CXD2880_TNRDMD_CFG_DVBT2_BBER_MES,
9039593810cSYasunari Takiguchi mes_exp);
9049593810cSYasunari Takiguchi
9059593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt2_mon_bbheader(&priv->tnrdmd,
9069593810cSYasunari Takiguchi CXD2880_DVBT2_PLP_DATA,
9079593810cSYasunari Takiguchi &bbheader);
9089593810cSYasunari Takiguchi if (ret) {
9099593810cSYasunari Takiguchi pr_info("bb header error\n");
9109593810cSYasunari Takiguchi goto error_ucblock_setting;
9119593810cSYasunari Takiguchi }
9129593810cSYasunari Takiguchi
9139593810cSYasunari Takiguchi if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_NM) {
9149593810cSYasunari Takiguchi if (!bbheader.issy_indicator) {
9159593810cSYasunari Takiguchi ucblock_rate =
9169593810cSYasunari Takiguchi (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] +
9179593810cSYasunari Takiguchi 752) / 1504;
9189593810cSYasunari Takiguchi } else {
9199593810cSYasunari Takiguchi ucblock_rate =
9209593810cSYasunari Takiguchi (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] +
9219593810cSYasunari Takiguchi 764) / 1528;
9229593810cSYasunari Takiguchi }
9239593810cSYasunari Takiguchi } else if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_HEM) {
9249593810cSYasunari Takiguchi ucblock_rate =
9259593810cSYasunari Takiguchi (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + 748) /
9269593810cSYasunari Takiguchi 1496;
9279593810cSYasunari Takiguchi } else {
9289593810cSYasunari Takiguchi pr_info("plp mode is not Normal or HEM\n");
9299593810cSYasunari Takiguchi goto error_ucblock_setting;
9309593810cSYasunari Takiguchi }
9319593810cSYasunari Takiguchi
9329593810cSYasunari Takiguchi mes_exp = intlog2(ucblock_rate) >> 24;
9339593810cSYasunari Takiguchi priv->ucblock_interval =
9349593810cSYasunari Takiguchi ((1U << mes_exp) * 1000 + (ucblock_rate / 2)) /
9359593810cSYasunari Takiguchi ucblock_rate;
9369593810cSYasunari Takiguchi cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
9379593810cSYasunari Takiguchi CXD2880_TNRDMD_CFG_DVBT2_PER_MES,
9389593810cSYasunari Takiguchi mes_exp);
9399593810cSYasunari Takiguchi
9409593810cSYasunari Takiguchi return 0;
9419593810cSYasunari Takiguchi
9429593810cSYasunari Takiguchi error_ber_setting:
9439593810cSYasunari Takiguchi priv->pre_ber_interval = 1000;
9449593810cSYasunari Takiguchi cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
9459593810cSYasunari Takiguchi CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, 0);
9469593810cSYasunari Takiguchi
9479593810cSYasunari Takiguchi priv->post_ber_interval = 1000;
9489593810cSYasunari Takiguchi cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
9499593810cSYasunari Takiguchi CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, 0);
9509593810cSYasunari Takiguchi
9519593810cSYasunari Takiguchi error_ucblock_setting:
9529593810cSYasunari Takiguchi priv->ucblock_interval = 1000;
9539593810cSYasunari Takiguchi cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
9549593810cSYasunari Takiguchi CXD2880_TNRDMD_CFG_DVBT2_PER_MES, 8);
9559593810cSYasunari Takiguchi
9569593810cSYasunari Takiguchi return 0;
9579593810cSYasunari Takiguchi }
9589593810cSYasunari Takiguchi
cxd2880_dvbt_tune(struct cxd2880_tnrdmd * tnr_dmd,struct cxd2880_dvbt_tune_param * tune_param)9599593810cSYasunari Takiguchi static int cxd2880_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd,
9609593810cSYasunari Takiguchi struct cxd2880_dvbt_tune_param
9619593810cSYasunari Takiguchi *tune_param)
9629593810cSYasunari Takiguchi {
9639593810cSYasunari Takiguchi int ret;
9649593810cSYasunari Takiguchi
9659593810cSYasunari Takiguchi if (!tnr_dmd || !tune_param)
9669593810cSYasunari Takiguchi return -EINVAL;
9679593810cSYasunari Takiguchi
9689593810cSYasunari Takiguchi if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
9699593810cSYasunari Takiguchi return -EINVAL;
9709593810cSYasunari Takiguchi
9719593810cSYasunari Takiguchi if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
9729593810cSYasunari Takiguchi tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
9739593810cSYasunari Takiguchi return -EINVAL;
9749593810cSYasunari Takiguchi
9759593810cSYasunari Takiguchi atomic_set(&tnr_dmd->cancel, 0);
9769593810cSYasunari Takiguchi
9779593810cSYasunari Takiguchi if (tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ &&
9789593810cSYasunari Takiguchi tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ &&
9799593810cSYasunari Takiguchi tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ &&
9809593810cSYasunari Takiguchi tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ) {
9819593810cSYasunari Takiguchi return -ENOTTY;
9829593810cSYasunari Takiguchi }
9839593810cSYasunari Takiguchi
9849593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt_tune1(tnr_dmd, tune_param);
9859593810cSYasunari Takiguchi if (ret)
9869593810cSYasunari Takiguchi return ret;
9879593810cSYasunari Takiguchi
9889593810cSYasunari Takiguchi usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000,
9899593810cSYasunari Takiguchi CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000);
9909593810cSYasunari Takiguchi
9919593810cSYasunari Takiguchi return cxd2880_tnrdmd_dvbt_tune2(tnr_dmd, tune_param);
9929593810cSYasunari Takiguchi }
9939593810cSYasunari Takiguchi
cxd2880_dvbt2_tune(struct cxd2880_tnrdmd * tnr_dmd,struct cxd2880_dvbt2_tune_param * tune_param)9949593810cSYasunari Takiguchi static int cxd2880_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd,
9959593810cSYasunari Takiguchi struct cxd2880_dvbt2_tune_param
9969593810cSYasunari Takiguchi *tune_param)
9979593810cSYasunari Takiguchi {
9989593810cSYasunari Takiguchi int ret;
9999593810cSYasunari Takiguchi
10009593810cSYasunari Takiguchi if (!tnr_dmd || !tune_param)
10019593810cSYasunari Takiguchi return -EINVAL;
10029593810cSYasunari Takiguchi
10039593810cSYasunari Takiguchi if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
10049593810cSYasunari Takiguchi return -EINVAL;
10059593810cSYasunari Takiguchi
10069593810cSYasunari Takiguchi if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
10079593810cSYasunari Takiguchi tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
10089593810cSYasunari Takiguchi return -EINVAL;
10099593810cSYasunari Takiguchi
10109593810cSYasunari Takiguchi atomic_set(&tnr_dmd->cancel, 0);
10119593810cSYasunari Takiguchi
10129593810cSYasunari Takiguchi if (tune_param->bandwidth != CXD2880_DTV_BW_1_7_MHZ &&
10139593810cSYasunari Takiguchi tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ &&
10149593810cSYasunari Takiguchi tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ &&
10159593810cSYasunari Takiguchi tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ &&
10169593810cSYasunari Takiguchi tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ) {
10179593810cSYasunari Takiguchi return -ENOTTY;
10189593810cSYasunari Takiguchi }
10199593810cSYasunari Takiguchi
10209593810cSYasunari Takiguchi if (tune_param->profile != CXD2880_DVBT2_PROFILE_BASE &&
10219593810cSYasunari Takiguchi tune_param->profile != CXD2880_DVBT2_PROFILE_LITE)
10229593810cSYasunari Takiguchi return -EINVAL;
10239593810cSYasunari Takiguchi
10249593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt2_tune1(tnr_dmd, tune_param);
10259593810cSYasunari Takiguchi if (ret)
10269593810cSYasunari Takiguchi return ret;
10279593810cSYasunari Takiguchi
10289593810cSYasunari Takiguchi usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000,
10299593810cSYasunari Takiguchi CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000);
10309593810cSYasunari Takiguchi
10319593810cSYasunari Takiguchi return cxd2880_tnrdmd_dvbt2_tune2(tnr_dmd, tune_param);
10329593810cSYasunari Takiguchi }
10339593810cSYasunari Takiguchi
cxd2880_set_frontend(struct dvb_frontend * fe)10349593810cSYasunari Takiguchi static int cxd2880_set_frontend(struct dvb_frontend *fe)
10359593810cSYasunari Takiguchi {
10369593810cSYasunari Takiguchi int ret;
10379593810cSYasunari Takiguchi struct dtv_frontend_properties *c;
10389593810cSYasunari Takiguchi struct cxd2880_priv *priv;
10399593810cSYasunari Takiguchi enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
10409593810cSYasunari Takiguchi
10419593810cSYasunari Takiguchi if (!fe) {
10429593810cSYasunari Takiguchi pr_err("invalid arg\n");
10439593810cSYasunari Takiguchi return -EINVAL;
10449593810cSYasunari Takiguchi }
10459593810cSYasunari Takiguchi
10469593810cSYasunari Takiguchi priv = fe->demodulator_priv;
10479593810cSYasunari Takiguchi c = &fe->dtv_property_cache;
10489593810cSYasunari Takiguchi
10499593810cSYasunari Takiguchi c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10509593810cSYasunari Takiguchi c->pre_bit_error.stat[0].uvalue = 0;
10519593810cSYasunari Takiguchi c->pre_bit_error.len = 1;
10529593810cSYasunari Takiguchi c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10539593810cSYasunari Takiguchi c->pre_bit_count.stat[0].uvalue = 0;
10549593810cSYasunari Takiguchi c->pre_bit_count.len = 1;
10559593810cSYasunari Takiguchi c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10569593810cSYasunari Takiguchi c->post_bit_error.stat[0].uvalue = 0;
10579593810cSYasunari Takiguchi c->post_bit_error.len = 1;
10589593810cSYasunari Takiguchi c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10599593810cSYasunari Takiguchi c->post_bit_count.stat[0].uvalue = 0;
10609593810cSYasunari Takiguchi c->post_bit_count.len = 1;
10619593810cSYasunari Takiguchi c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10629593810cSYasunari Takiguchi c->block_error.stat[0].uvalue = 0;
10639593810cSYasunari Takiguchi c->block_error.len = 1;
10649593810cSYasunari Takiguchi c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10659593810cSYasunari Takiguchi c->block_count.stat[0].uvalue = 0;
10669593810cSYasunari Takiguchi c->block_count.len = 1;
10679593810cSYasunari Takiguchi
10689593810cSYasunari Takiguchi switch (c->bandwidth_hz) {
10699593810cSYasunari Takiguchi case 1712000:
10709593810cSYasunari Takiguchi bw = CXD2880_DTV_BW_1_7_MHZ;
10719593810cSYasunari Takiguchi break;
10729593810cSYasunari Takiguchi case 5000000:
10739593810cSYasunari Takiguchi bw = CXD2880_DTV_BW_5_MHZ;
10749593810cSYasunari Takiguchi break;
10759593810cSYasunari Takiguchi case 6000000:
10769593810cSYasunari Takiguchi bw = CXD2880_DTV_BW_6_MHZ;
10779593810cSYasunari Takiguchi break;
10789593810cSYasunari Takiguchi case 7000000:
10799593810cSYasunari Takiguchi bw = CXD2880_DTV_BW_7_MHZ;
10809593810cSYasunari Takiguchi break;
10819593810cSYasunari Takiguchi case 8000000:
10829593810cSYasunari Takiguchi bw = CXD2880_DTV_BW_8_MHZ;
10839593810cSYasunari Takiguchi break;
10849593810cSYasunari Takiguchi default:
10859593810cSYasunari Takiguchi return -EINVAL;
10869593810cSYasunari Takiguchi }
10879593810cSYasunari Takiguchi
10889593810cSYasunari Takiguchi priv->s = 0;
10899593810cSYasunari Takiguchi
10909593810cSYasunari Takiguchi pr_info("sys:%d freq:%d bw:%d\n",
10919593810cSYasunari Takiguchi c->delivery_system, c->frequency, bw);
10929593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
10939593810cSYasunari Takiguchi if (c->delivery_system == SYS_DVBT) {
10949593810cSYasunari Takiguchi priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT;
10959593810cSYasunari Takiguchi priv->dvbt_tune_param.center_freq_khz = c->frequency / 1000;
10969593810cSYasunari Takiguchi priv->dvbt_tune_param.bandwidth = bw;
10979593810cSYasunari Takiguchi priv->dvbt_tune_param.profile = CXD2880_DVBT_PROFILE_HP;
10989593810cSYasunari Takiguchi ret = cxd2880_dvbt_tune(&priv->tnrdmd,
10999593810cSYasunari Takiguchi &priv->dvbt_tune_param);
11009593810cSYasunari Takiguchi } else if (c->delivery_system == SYS_DVBT2) {
11019593810cSYasunari Takiguchi priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT2;
11029593810cSYasunari Takiguchi priv->dvbt2_tune_param.center_freq_khz = c->frequency / 1000;
11039593810cSYasunari Takiguchi priv->dvbt2_tune_param.bandwidth = bw;
11049593810cSYasunari Takiguchi priv->dvbt2_tune_param.data_plp_id = (u16)c->stream_id;
11059593810cSYasunari Takiguchi priv->dvbt2_tune_param.profile = CXD2880_DVBT2_PROFILE_BASE;
11069593810cSYasunari Takiguchi ret = cxd2880_dvbt2_tune(&priv->tnrdmd,
11079593810cSYasunari Takiguchi &priv->dvbt2_tune_param);
11089593810cSYasunari Takiguchi } else {
11099593810cSYasunari Takiguchi pr_err("invalid system\n");
11109593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
11119593810cSYasunari Takiguchi return -EINVAL;
11129593810cSYasunari Takiguchi }
11139593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
11149593810cSYasunari Takiguchi
11159593810cSYasunari Takiguchi pr_info("tune result %d\n", ret);
11169593810cSYasunari Takiguchi
11179593810cSYasunari Takiguchi return ret;
11189593810cSYasunari Takiguchi }
11199593810cSYasunari Takiguchi
cxd2880_get_stats(struct dvb_frontend * fe,enum fe_status status)11209593810cSYasunari Takiguchi static int cxd2880_get_stats(struct dvb_frontend *fe,
11219593810cSYasunari Takiguchi enum fe_status status)
11229593810cSYasunari Takiguchi {
11239593810cSYasunari Takiguchi struct cxd2880_priv *priv = NULL;
11249593810cSYasunari Takiguchi struct dtv_frontend_properties *c = NULL;
11259593810cSYasunari Takiguchi u32 pre_bit_err = 0, pre_bit_count = 0;
11269593810cSYasunari Takiguchi u32 post_bit_err = 0, post_bit_count = 0;
11279593810cSYasunari Takiguchi u32 block_err = 0, block_count = 0;
11289593810cSYasunari Takiguchi int ret;
11299593810cSYasunari Takiguchi
11309593810cSYasunari Takiguchi if (!fe) {
11319593810cSYasunari Takiguchi pr_err("invalid arg\n");
11329593810cSYasunari Takiguchi return -EINVAL;
11339593810cSYasunari Takiguchi }
11349593810cSYasunari Takiguchi
11359593810cSYasunari Takiguchi priv = fe->demodulator_priv;
11369593810cSYasunari Takiguchi c = &fe->dtv_property_cache;
11379593810cSYasunari Takiguchi
1138f2e7af0bSYasunari Takiguchi if (!(status & FE_HAS_LOCK) || !(status & FE_HAS_CARRIER)) {
11399593810cSYasunari Takiguchi c->pre_bit_error.len = 1;
11409593810cSYasunari Takiguchi c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
11419593810cSYasunari Takiguchi c->pre_bit_count.len = 1;
11429593810cSYasunari Takiguchi c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
11439593810cSYasunari Takiguchi c->post_bit_error.len = 1;
11449593810cSYasunari Takiguchi c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
11459593810cSYasunari Takiguchi c->post_bit_count.len = 1;
11469593810cSYasunari Takiguchi c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
11479593810cSYasunari Takiguchi c->block_error.len = 1;
11489593810cSYasunari Takiguchi c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
11499593810cSYasunari Takiguchi c->block_count.len = 1;
11509593810cSYasunari Takiguchi c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
11519593810cSYasunari Takiguchi
11529593810cSYasunari Takiguchi return 0;
11539593810cSYasunari Takiguchi }
11549593810cSYasunari Takiguchi
11559593810cSYasunari Takiguchi if (time_after(jiffies, priv->pre_ber_update)) {
11569593810cSYasunari Takiguchi priv->pre_ber_update =
11579593810cSYasunari Takiguchi jiffies + msecs_to_jiffies(priv->pre_ber_interval);
11589593810cSYasunari Takiguchi if (c->delivery_system == SYS_DVBT) {
11599593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
11609593810cSYasunari Takiguchi ret = cxd2880_pre_bit_err_t(&priv->tnrdmd,
11619593810cSYasunari Takiguchi &pre_bit_err,
11629593810cSYasunari Takiguchi &pre_bit_count);
11639593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
11649593810cSYasunari Takiguchi } else if (c->delivery_system == SYS_DVBT2) {
11659593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
11669593810cSYasunari Takiguchi ret = cxd2880_pre_bit_err_t2(&priv->tnrdmd,
11679593810cSYasunari Takiguchi &pre_bit_err,
11689593810cSYasunari Takiguchi &pre_bit_count);
11699593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
11709593810cSYasunari Takiguchi } else {
11719593810cSYasunari Takiguchi return -EINVAL;
11729593810cSYasunari Takiguchi }
11739593810cSYasunari Takiguchi
11749593810cSYasunari Takiguchi if (!ret) {
11759593810cSYasunari Takiguchi c->pre_bit_error.len = 1;
11769593810cSYasunari Takiguchi c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
11779593810cSYasunari Takiguchi c->pre_bit_error.stat[0].uvalue += pre_bit_err;
11789593810cSYasunari Takiguchi c->pre_bit_count.len = 1;
11799593810cSYasunari Takiguchi c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
11809593810cSYasunari Takiguchi c->pre_bit_count.stat[0].uvalue += pre_bit_count;
11819593810cSYasunari Takiguchi } else {
11829593810cSYasunari Takiguchi c->pre_bit_error.len = 1;
11839593810cSYasunari Takiguchi c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
11849593810cSYasunari Takiguchi c->pre_bit_count.len = 1;
11859593810cSYasunari Takiguchi c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
11869593810cSYasunari Takiguchi pr_debug("pre_bit_error_t failed %d\n", ret);
11879593810cSYasunari Takiguchi }
11889593810cSYasunari Takiguchi }
11899593810cSYasunari Takiguchi
11909593810cSYasunari Takiguchi if (time_after(jiffies, priv->post_ber_update)) {
11919593810cSYasunari Takiguchi priv->post_ber_update =
11929593810cSYasunari Takiguchi jiffies + msecs_to_jiffies(priv->post_ber_interval);
11939593810cSYasunari Takiguchi if (c->delivery_system == SYS_DVBT) {
11949593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
11959593810cSYasunari Takiguchi ret = cxd2880_post_bit_err_t(&priv->tnrdmd,
11969593810cSYasunari Takiguchi &post_bit_err,
11979593810cSYasunari Takiguchi &post_bit_count);
11989593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
11999593810cSYasunari Takiguchi } else if (c->delivery_system == SYS_DVBT2) {
12009593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
12019593810cSYasunari Takiguchi ret = cxd2880_post_bit_err_t2(&priv->tnrdmd,
12029593810cSYasunari Takiguchi &post_bit_err,
12039593810cSYasunari Takiguchi &post_bit_count);
12049593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
12059593810cSYasunari Takiguchi } else {
12069593810cSYasunari Takiguchi return -EINVAL;
12079593810cSYasunari Takiguchi }
12089593810cSYasunari Takiguchi
12099593810cSYasunari Takiguchi if (!ret) {
12109593810cSYasunari Takiguchi c->post_bit_error.len = 1;
12119593810cSYasunari Takiguchi c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
12129593810cSYasunari Takiguchi c->post_bit_error.stat[0].uvalue += post_bit_err;
12139593810cSYasunari Takiguchi c->post_bit_count.len = 1;
12149593810cSYasunari Takiguchi c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
12159593810cSYasunari Takiguchi c->post_bit_count.stat[0].uvalue += post_bit_count;
12169593810cSYasunari Takiguchi } else {
12179593810cSYasunari Takiguchi c->post_bit_error.len = 1;
12189593810cSYasunari Takiguchi c->post_bit_error.stat[0].scale =
12199593810cSYasunari Takiguchi FE_SCALE_NOT_AVAILABLE;
12209593810cSYasunari Takiguchi c->post_bit_count.len = 1;
12219593810cSYasunari Takiguchi c->post_bit_count.stat[0].scale =
12229593810cSYasunari Takiguchi FE_SCALE_NOT_AVAILABLE;
12239593810cSYasunari Takiguchi pr_debug("post_bit_err_t %d\n", ret);
12249593810cSYasunari Takiguchi }
12259593810cSYasunari Takiguchi }
12269593810cSYasunari Takiguchi
12279593810cSYasunari Takiguchi if (time_after(jiffies, priv->ucblock_update)) {
12289593810cSYasunari Takiguchi priv->ucblock_update =
12299593810cSYasunari Takiguchi jiffies + msecs_to_jiffies(priv->ucblock_interval);
12309593810cSYasunari Takiguchi if (c->delivery_system == SYS_DVBT) {
12319593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
12329593810cSYasunari Takiguchi ret = cxd2880_read_block_err_t(&priv->tnrdmd,
12339593810cSYasunari Takiguchi &block_err,
12349593810cSYasunari Takiguchi &block_count);
12359593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
12369593810cSYasunari Takiguchi } else if (c->delivery_system == SYS_DVBT2) {
12379593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
12389593810cSYasunari Takiguchi ret = cxd2880_read_block_err_t2(&priv->tnrdmd,
12399593810cSYasunari Takiguchi &block_err,
12409593810cSYasunari Takiguchi &block_count);
12419593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
12429593810cSYasunari Takiguchi } else {
12439593810cSYasunari Takiguchi return -EINVAL;
12449593810cSYasunari Takiguchi }
12459593810cSYasunari Takiguchi if (!ret) {
12469593810cSYasunari Takiguchi c->block_error.len = 1;
12479593810cSYasunari Takiguchi c->block_error.stat[0].scale = FE_SCALE_COUNTER;
12489593810cSYasunari Takiguchi c->block_error.stat[0].uvalue += block_err;
12499593810cSYasunari Takiguchi c->block_count.len = 1;
12509593810cSYasunari Takiguchi c->block_count.stat[0].scale = FE_SCALE_COUNTER;
12519593810cSYasunari Takiguchi c->block_count.stat[0].uvalue += block_count;
12529593810cSYasunari Takiguchi } else {
12539593810cSYasunari Takiguchi c->block_error.len = 1;
12549593810cSYasunari Takiguchi c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
12559593810cSYasunari Takiguchi c->block_count.len = 1;
12569593810cSYasunari Takiguchi c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
12579593810cSYasunari Takiguchi pr_debug("read_block_err_t %d\n", ret);
12589593810cSYasunari Takiguchi }
12599593810cSYasunari Takiguchi }
12609593810cSYasunari Takiguchi
12619593810cSYasunari Takiguchi return 0;
12629593810cSYasunari Takiguchi }
12639593810cSYasunari Takiguchi
cxd2880_check_l1post_plp(struct dvb_frontend * fe)12649593810cSYasunari Takiguchi static int cxd2880_check_l1post_plp(struct dvb_frontend *fe)
12659593810cSYasunari Takiguchi {
12669593810cSYasunari Takiguchi u8 valid = 0;
12679593810cSYasunari Takiguchi u8 plp_not_found;
12689593810cSYasunari Takiguchi int ret;
12699593810cSYasunari Takiguchi struct cxd2880_priv *priv = NULL;
12709593810cSYasunari Takiguchi
12719593810cSYasunari Takiguchi if (!fe) {
12729593810cSYasunari Takiguchi pr_err("invalid arg\n");
12739593810cSYasunari Takiguchi return -EINVAL;
12749593810cSYasunari Takiguchi }
12759593810cSYasunari Takiguchi
12769593810cSYasunari Takiguchi priv = fe->demodulator_priv;
12779593810cSYasunari Takiguchi
12789593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt2_check_l1post_valid(&priv->tnrdmd,
12799593810cSYasunari Takiguchi &valid);
12809593810cSYasunari Takiguchi if (ret)
12819593810cSYasunari Takiguchi return ret;
12829593810cSYasunari Takiguchi
12839593810cSYasunari Takiguchi if (!valid)
12849593810cSYasunari Takiguchi return -EAGAIN;
12859593810cSYasunari Takiguchi
12869593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt2_mon_data_plp_error(&priv->tnrdmd,
12879593810cSYasunari Takiguchi &plp_not_found);
12889593810cSYasunari Takiguchi if (ret)
12899593810cSYasunari Takiguchi return ret;
12909593810cSYasunari Takiguchi
12919593810cSYasunari Takiguchi if (plp_not_found) {
12929593810cSYasunari Takiguchi priv->dvbt2_tune_param.tune_info =
12939593810cSYasunari Takiguchi CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID;
12949593810cSYasunari Takiguchi } else {
12959593810cSYasunari Takiguchi priv->dvbt2_tune_param.tune_info =
12969593810cSYasunari Takiguchi CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK;
12979593810cSYasunari Takiguchi }
12989593810cSYasunari Takiguchi
12999593810cSYasunari Takiguchi return 0;
13009593810cSYasunari Takiguchi }
13019593810cSYasunari Takiguchi
cxd2880_read_status(struct dvb_frontend * fe,enum fe_status * status)13029593810cSYasunari Takiguchi static int cxd2880_read_status(struct dvb_frontend *fe,
13039593810cSYasunari Takiguchi enum fe_status *status)
13049593810cSYasunari Takiguchi {
13059593810cSYasunari Takiguchi int ret;
13069593810cSYasunari Takiguchi u8 sync = 0;
13079593810cSYasunari Takiguchi u8 lock = 0;
13089593810cSYasunari Takiguchi u8 unlock = 0;
13099593810cSYasunari Takiguchi struct cxd2880_priv *priv = NULL;
13109593810cSYasunari Takiguchi struct dtv_frontend_properties *c = NULL;
13119593810cSYasunari Takiguchi
13129593810cSYasunari Takiguchi if (!fe || !status) {
13139593810cSYasunari Takiguchi pr_err("invalid arg\n");
13149593810cSYasunari Takiguchi return -EINVAL;
13159593810cSYasunari Takiguchi }
13169593810cSYasunari Takiguchi
13179593810cSYasunari Takiguchi priv = fe->demodulator_priv;
13189593810cSYasunari Takiguchi c = &fe->dtv_property_cache;
13199593810cSYasunari Takiguchi *status = 0;
13209593810cSYasunari Takiguchi
13219593810cSYasunari Takiguchi if (priv->tnrdmd.state == CXD2880_TNRDMD_STATE_ACTIVE) {
13229593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
13239593810cSYasunari Takiguchi if (c->delivery_system == SYS_DVBT) {
13249593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt_mon_sync_stat(&priv->tnrdmd,
13259593810cSYasunari Takiguchi &sync,
13269593810cSYasunari Takiguchi &lock,
13279593810cSYasunari Takiguchi &unlock);
13289593810cSYasunari Takiguchi } else if (c->delivery_system == SYS_DVBT2) {
13299593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat(&priv->tnrdmd,
13309593810cSYasunari Takiguchi &sync,
13319593810cSYasunari Takiguchi &lock,
13329593810cSYasunari Takiguchi &unlock);
13339593810cSYasunari Takiguchi } else {
13349593810cSYasunari Takiguchi pr_err("invalid system");
13359593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
13369593810cSYasunari Takiguchi return -EINVAL;
13379593810cSYasunari Takiguchi }
13389593810cSYasunari Takiguchi
13399593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
13409593810cSYasunari Takiguchi if (ret) {
13419593810cSYasunari Takiguchi pr_err("failed. sys = %d\n", priv->tnrdmd.sys);
13429593810cSYasunari Takiguchi return ret;
13439593810cSYasunari Takiguchi }
13449593810cSYasunari Takiguchi
13459593810cSYasunari Takiguchi if (sync == 6) {
13469593810cSYasunari Takiguchi *status = FE_HAS_SIGNAL |
13479593810cSYasunari Takiguchi FE_HAS_CARRIER;
13489593810cSYasunari Takiguchi }
13499593810cSYasunari Takiguchi if (lock)
13509593810cSYasunari Takiguchi *status |= FE_HAS_VITERBI |
13519593810cSYasunari Takiguchi FE_HAS_SYNC |
13529593810cSYasunari Takiguchi FE_HAS_LOCK;
13539593810cSYasunari Takiguchi }
13549593810cSYasunari Takiguchi
13559593810cSYasunari Takiguchi pr_debug("status %d\n", *status);
13569593810cSYasunari Takiguchi
1357f2e7af0bSYasunari Takiguchi if (priv->s == 0 && (*status & FE_HAS_LOCK) &&
1358f2e7af0bSYasunari Takiguchi (*status & FE_HAS_CARRIER)) {
13599593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
13609593810cSYasunari Takiguchi if (c->delivery_system == SYS_DVBT) {
13619593810cSYasunari Takiguchi ret = cxd2880_set_ber_per_period_t(fe);
13629593810cSYasunari Takiguchi priv->s = *status;
13639593810cSYasunari Takiguchi } else if (c->delivery_system == SYS_DVBT2) {
13649593810cSYasunari Takiguchi ret = cxd2880_check_l1post_plp(fe);
13659593810cSYasunari Takiguchi if (!ret) {
13669593810cSYasunari Takiguchi ret = cxd2880_set_ber_per_period_t2(fe);
13679593810cSYasunari Takiguchi priv->s = *status;
13689593810cSYasunari Takiguchi }
13699593810cSYasunari Takiguchi } else {
13709593810cSYasunari Takiguchi pr_err("invalid system\n");
13719593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
13729593810cSYasunari Takiguchi return -EINVAL;
13739593810cSYasunari Takiguchi }
13749593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
13759593810cSYasunari Takiguchi }
13769593810cSYasunari Takiguchi
13779593810cSYasunari Takiguchi cxd2880_get_stats(fe, *status);
13789593810cSYasunari Takiguchi return 0;
13799593810cSYasunari Takiguchi }
13809593810cSYasunari Takiguchi
cxd2880_tune(struct dvb_frontend * fe,bool retune,unsigned int mode_flags,unsigned int * delay,enum fe_status * status)13819593810cSYasunari Takiguchi static int cxd2880_tune(struct dvb_frontend *fe,
13829593810cSYasunari Takiguchi bool retune,
13839593810cSYasunari Takiguchi unsigned int mode_flags,
13849593810cSYasunari Takiguchi unsigned int *delay,
13859593810cSYasunari Takiguchi enum fe_status *status)
13869593810cSYasunari Takiguchi {
13879593810cSYasunari Takiguchi int ret;
13889593810cSYasunari Takiguchi
13899593810cSYasunari Takiguchi if (!fe || !delay || !status) {
13909593810cSYasunari Takiguchi pr_err("invalid arg.");
13919593810cSYasunari Takiguchi return -EINVAL;
13929593810cSYasunari Takiguchi }
13939593810cSYasunari Takiguchi
13949593810cSYasunari Takiguchi if (retune) {
13959593810cSYasunari Takiguchi ret = cxd2880_set_frontend(fe);
13969593810cSYasunari Takiguchi if (ret) {
13979593810cSYasunari Takiguchi pr_err("cxd2880_set_frontend failed %d\n", ret);
13989593810cSYasunari Takiguchi return ret;
13999593810cSYasunari Takiguchi }
14009593810cSYasunari Takiguchi }
14019593810cSYasunari Takiguchi
14029593810cSYasunari Takiguchi *delay = HZ / 5;
14039593810cSYasunari Takiguchi
14049593810cSYasunari Takiguchi return cxd2880_read_status(fe, status);
14059593810cSYasunari Takiguchi }
14069593810cSYasunari Takiguchi
cxd2880_get_frontend_t(struct dvb_frontend * fe,struct dtv_frontend_properties * c)14079593810cSYasunari Takiguchi static int cxd2880_get_frontend_t(struct dvb_frontend *fe,
14089593810cSYasunari Takiguchi struct dtv_frontend_properties *c)
14099593810cSYasunari Takiguchi {
14109593810cSYasunari Takiguchi int ret;
14119593810cSYasunari Takiguchi struct cxd2880_priv *priv = NULL;
14129593810cSYasunari Takiguchi enum cxd2880_dvbt_mode mode = CXD2880_DVBT_MODE_2K;
14139593810cSYasunari Takiguchi enum cxd2880_dvbt_guard guard = CXD2880_DVBT_GUARD_1_32;
14149593810cSYasunari Takiguchi struct cxd2880_dvbt_tpsinfo tps;
14159593810cSYasunari Takiguchi enum cxd2880_tnrdmd_spectrum_sense sense;
14169593810cSYasunari Takiguchi u16 snr = 0;
14179593810cSYasunari Takiguchi int strength = 0;
14189593810cSYasunari Takiguchi
14199593810cSYasunari Takiguchi if (!fe || !c) {
14209593810cSYasunari Takiguchi pr_err("invalid arg\n");
14219593810cSYasunari Takiguchi return -EINVAL;
14229593810cSYasunari Takiguchi }
14239593810cSYasunari Takiguchi
14249593810cSYasunari Takiguchi priv = fe->demodulator_priv;
14259593810cSYasunari Takiguchi
14269593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
14279593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt_mon_mode_guard(&priv->tnrdmd,
14289593810cSYasunari Takiguchi &mode, &guard);
14299593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
14309593810cSYasunari Takiguchi if (!ret) {
14319593810cSYasunari Takiguchi switch (mode) {
14329593810cSYasunari Takiguchi case CXD2880_DVBT_MODE_2K:
14339593810cSYasunari Takiguchi c->transmission_mode = TRANSMISSION_MODE_2K;
14349593810cSYasunari Takiguchi break;
14359593810cSYasunari Takiguchi case CXD2880_DVBT_MODE_8K:
14369593810cSYasunari Takiguchi c->transmission_mode = TRANSMISSION_MODE_8K;
14379593810cSYasunari Takiguchi break;
14389593810cSYasunari Takiguchi default:
14399593810cSYasunari Takiguchi c->transmission_mode = TRANSMISSION_MODE_2K;
14409593810cSYasunari Takiguchi pr_debug("transmission mode is invalid %d\n", mode);
14419593810cSYasunari Takiguchi break;
14429593810cSYasunari Takiguchi }
14439593810cSYasunari Takiguchi switch (guard) {
14449593810cSYasunari Takiguchi case CXD2880_DVBT_GUARD_1_32:
14459593810cSYasunari Takiguchi c->guard_interval = GUARD_INTERVAL_1_32;
14469593810cSYasunari Takiguchi break;
14479593810cSYasunari Takiguchi case CXD2880_DVBT_GUARD_1_16:
14489593810cSYasunari Takiguchi c->guard_interval = GUARD_INTERVAL_1_16;
14499593810cSYasunari Takiguchi break;
14509593810cSYasunari Takiguchi case CXD2880_DVBT_GUARD_1_8:
14519593810cSYasunari Takiguchi c->guard_interval = GUARD_INTERVAL_1_8;
14529593810cSYasunari Takiguchi break;
14539593810cSYasunari Takiguchi case CXD2880_DVBT_GUARD_1_4:
14549593810cSYasunari Takiguchi c->guard_interval = GUARD_INTERVAL_1_4;
14559593810cSYasunari Takiguchi break;
14569593810cSYasunari Takiguchi default:
14579593810cSYasunari Takiguchi c->guard_interval = GUARD_INTERVAL_1_32;
14589593810cSYasunari Takiguchi pr_debug("guard interval is invalid %d\n",
14599593810cSYasunari Takiguchi guard);
14609593810cSYasunari Takiguchi break;
14619593810cSYasunari Takiguchi }
14629593810cSYasunari Takiguchi } else {
14639593810cSYasunari Takiguchi c->transmission_mode = TRANSMISSION_MODE_2K;
14649593810cSYasunari Takiguchi c->guard_interval = GUARD_INTERVAL_1_32;
14659593810cSYasunari Takiguchi pr_debug("ModeGuard err %d\n", ret);
14669593810cSYasunari Takiguchi }
14679593810cSYasunari Takiguchi
14689593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
14699593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, &tps);
14709593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
14719593810cSYasunari Takiguchi if (!ret) {
14729593810cSYasunari Takiguchi switch (tps.hierarchy) {
14739593810cSYasunari Takiguchi case CXD2880_DVBT_HIERARCHY_NON:
14749593810cSYasunari Takiguchi c->hierarchy = HIERARCHY_NONE;
14759593810cSYasunari Takiguchi break;
14769593810cSYasunari Takiguchi case CXD2880_DVBT_HIERARCHY_1:
14779593810cSYasunari Takiguchi c->hierarchy = HIERARCHY_1;
14789593810cSYasunari Takiguchi break;
14799593810cSYasunari Takiguchi case CXD2880_DVBT_HIERARCHY_2:
14809593810cSYasunari Takiguchi c->hierarchy = HIERARCHY_2;
14819593810cSYasunari Takiguchi break;
14829593810cSYasunari Takiguchi case CXD2880_DVBT_HIERARCHY_4:
14839593810cSYasunari Takiguchi c->hierarchy = HIERARCHY_4;
14849593810cSYasunari Takiguchi break;
14859593810cSYasunari Takiguchi default:
14869593810cSYasunari Takiguchi c->hierarchy = HIERARCHY_NONE;
14879593810cSYasunari Takiguchi pr_debug("TPSInfo hierarchy is invalid %d\n",
14889593810cSYasunari Takiguchi tps.hierarchy);
14899593810cSYasunari Takiguchi break;
14909593810cSYasunari Takiguchi }
14919593810cSYasunari Takiguchi
14929593810cSYasunari Takiguchi switch (tps.rate_hp) {
14939593810cSYasunari Takiguchi case CXD2880_DVBT_CODERATE_1_2:
14949593810cSYasunari Takiguchi c->code_rate_HP = FEC_1_2;
14959593810cSYasunari Takiguchi break;
14969593810cSYasunari Takiguchi case CXD2880_DVBT_CODERATE_2_3:
14979593810cSYasunari Takiguchi c->code_rate_HP = FEC_2_3;
14989593810cSYasunari Takiguchi break;
14999593810cSYasunari Takiguchi case CXD2880_DVBT_CODERATE_3_4:
15009593810cSYasunari Takiguchi c->code_rate_HP = FEC_3_4;
15019593810cSYasunari Takiguchi break;
15029593810cSYasunari Takiguchi case CXD2880_DVBT_CODERATE_5_6:
15039593810cSYasunari Takiguchi c->code_rate_HP = FEC_5_6;
15049593810cSYasunari Takiguchi break;
15059593810cSYasunari Takiguchi case CXD2880_DVBT_CODERATE_7_8:
15069593810cSYasunari Takiguchi c->code_rate_HP = FEC_7_8;
15079593810cSYasunari Takiguchi break;
15089593810cSYasunari Takiguchi default:
15099593810cSYasunari Takiguchi c->code_rate_HP = FEC_NONE;
15109593810cSYasunari Takiguchi pr_debug("TPSInfo rateHP is invalid %d\n",
15119593810cSYasunari Takiguchi tps.rate_hp);
15129593810cSYasunari Takiguchi break;
15139593810cSYasunari Takiguchi }
15149593810cSYasunari Takiguchi switch (tps.rate_lp) {
15159593810cSYasunari Takiguchi case CXD2880_DVBT_CODERATE_1_2:
15169593810cSYasunari Takiguchi c->code_rate_LP = FEC_1_2;
15179593810cSYasunari Takiguchi break;
15189593810cSYasunari Takiguchi case CXD2880_DVBT_CODERATE_2_3:
15199593810cSYasunari Takiguchi c->code_rate_LP = FEC_2_3;
15209593810cSYasunari Takiguchi break;
15219593810cSYasunari Takiguchi case CXD2880_DVBT_CODERATE_3_4:
15229593810cSYasunari Takiguchi c->code_rate_LP = FEC_3_4;
15239593810cSYasunari Takiguchi break;
15249593810cSYasunari Takiguchi case CXD2880_DVBT_CODERATE_5_6:
15259593810cSYasunari Takiguchi c->code_rate_LP = FEC_5_6;
15269593810cSYasunari Takiguchi break;
15279593810cSYasunari Takiguchi case CXD2880_DVBT_CODERATE_7_8:
15289593810cSYasunari Takiguchi c->code_rate_LP = FEC_7_8;
15299593810cSYasunari Takiguchi break;
15309593810cSYasunari Takiguchi default:
15319593810cSYasunari Takiguchi c->code_rate_LP = FEC_NONE;
15329593810cSYasunari Takiguchi pr_debug("TPSInfo rateLP is invalid %d\n",
15339593810cSYasunari Takiguchi tps.rate_lp);
15349593810cSYasunari Takiguchi break;
15359593810cSYasunari Takiguchi }
15369593810cSYasunari Takiguchi switch (tps.constellation) {
15379593810cSYasunari Takiguchi case CXD2880_DVBT_CONSTELLATION_QPSK:
15389593810cSYasunari Takiguchi c->modulation = QPSK;
15399593810cSYasunari Takiguchi break;
15409593810cSYasunari Takiguchi case CXD2880_DVBT_CONSTELLATION_16QAM:
15419593810cSYasunari Takiguchi c->modulation = QAM_16;
15429593810cSYasunari Takiguchi break;
15439593810cSYasunari Takiguchi case CXD2880_DVBT_CONSTELLATION_64QAM:
15449593810cSYasunari Takiguchi c->modulation = QAM_64;
15459593810cSYasunari Takiguchi break;
15469593810cSYasunari Takiguchi default:
15479593810cSYasunari Takiguchi c->modulation = QPSK;
15489593810cSYasunari Takiguchi pr_debug("TPSInfo constellation is invalid %d\n",
15499593810cSYasunari Takiguchi tps.constellation);
15509593810cSYasunari Takiguchi break;
15519593810cSYasunari Takiguchi }
15529593810cSYasunari Takiguchi } else {
15539593810cSYasunari Takiguchi c->hierarchy = HIERARCHY_NONE;
15549593810cSYasunari Takiguchi c->code_rate_HP = FEC_NONE;
15559593810cSYasunari Takiguchi c->code_rate_LP = FEC_NONE;
15569593810cSYasunari Takiguchi c->modulation = QPSK;
15579593810cSYasunari Takiguchi pr_debug("TPS info err %d\n", ret);
15589593810cSYasunari Takiguchi }
15599593810cSYasunari Takiguchi
15609593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
15619593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(&priv->tnrdmd, &sense);
15629593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
15639593810cSYasunari Takiguchi if (!ret) {
15649593810cSYasunari Takiguchi switch (sense) {
15659593810cSYasunari Takiguchi case CXD2880_TNRDMD_SPECTRUM_NORMAL:
15669593810cSYasunari Takiguchi c->inversion = INVERSION_OFF;
15679593810cSYasunari Takiguchi break;
15689593810cSYasunari Takiguchi case CXD2880_TNRDMD_SPECTRUM_INV:
15699593810cSYasunari Takiguchi c->inversion = INVERSION_ON;
15709593810cSYasunari Takiguchi break;
15719593810cSYasunari Takiguchi default:
15729593810cSYasunari Takiguchi c->inversion = INVERSION_OFF;
15739593810cSYasunari Takiguchi pr_debug("spectrum sense is invalid %d\n", sense);
15749593810cSYasunari Takiguchi break;
15759593810cSYasunari Takiguchi }
15769593810cSYasunari Takiguchi } else {
15779593810cSYasunari Takiguchi c->inversion = INVERSION_OFF;
15789593810cSYasunari Takiguchi pr_debug("spectrum_sense %d\n", ret);
15799593810cSYasunari Takiguchi }
15809593810cSYasunari Takiguchi
15819593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
15829593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength);
15839593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
15849593810cSYasunari Takiguchi if (!ret) {
15859593810cSYasunari Takiguchi c->strength.len = 1;
15869593810cSYasunari Takiguchi c->strength.stat[0].scale = FE_SCALE_DECIBEL;
15879593810cSYasunari Takiguchi c->strength.stat[0].svalue = strength;
15889593810cSYasunari Takiguchi } else {
15899593810cSYasunari Takiguchi c->strength.len = 1;
15909593810cSYasunari Takiguchi c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
15919593810cSYasunari Takiguchi pr_debug("mon_rf_lvl %d\n", ret);
15929593810cSYasunari Takiguchi }
15939593810cSYasunari Takiguchi
15949593810cSYasunari Takiguchi ret = cxd2880_read_snr(fe, &snr);
15959593810cSYasunari Takiguchi if (!ret) {
15969593810cSYasunari Takiguchi c->cnr.len = 1;
15979593810cSYasunari Takiguchi c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
15989593810cSYasunari Takiguchi c->cnr.stat[0].svalue = snr;
15999593810cSYasunari Takiguchi } else {
16009593810cSYasunari Takiguchi c->cnr.len = 1;
16019593810cSYasunari Takiguchi c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
16029593810cSYasunari Takiguchi pr_debug("read_snr %d\n", ret);
16039593810cSYasunari Takiguchi }
16049593810cSYasunari Takiguchi
16059593810cSYasunari Takiguchi return 0;
16069593810cSYasunari Takiguchi }
16079593810cSYasunari Takiguchi
cxd2880_get_frontend_t2(struct dvb_frontend * fe,struct dtv_frontend_properties * c)16089593810cSYasunari Takiguchi static int cxd2880_get_frontend_t2(struct dvb_frontend *fe,
16099593810cSYasunari Takiguchi struct dtv_frontend_properties *c)
16109593810cSYasunari Takiguchi {
16119593810cSYasunari Takiguchi int ret;
16129593810cSYasunari Takiguchi struct cxd2880_priv *priv = NULL;
16139593810cSYasunari Takiguchi struct cxd2880_dvbt2_l1pre l1pre;
16149593810cSYasunari Takiguchi enum cxd2880_dvbt2_plp_code_rate coderate;
16159593810cSYasunari Takiguchi enum cxd2880_dvbt2_plp_constell qam;
16169593810cSYasunari Takiguchi enum cxd2880_tnrdmd_spectrum_sense sense;
16179593810cSYasunari Takiguchi u16 snr = 0;
16189593810cSYasunari Takiguchi int strength = 0;
16199593810cSYasunari Takiguchi
16209593810cSYasunari Takiguchi if (!fe || !c) {
16219593810cSYasunari Takiguchi pr_err("invalid arg.\n");
16229593810cSYasunari Takiguchi return -EINVAL;
16239593810cSYasunari Takiguchi }
16249593810cSYasunari Takiguchi
16259593810cSYasunari Takiguchi priv = fe->demodulator_priv;
16269593810cSYasunari Takiguchi
16279593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
16289593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre);
16299593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
16309593810cSYasunari Takiguchi if (!ret) {
16319593810cSYasunari Takiguchi switch (l1pre.fft_mode) {
16329593810cSYasunari Takiguchi case CXD2880_DVBT2_M2K:
16339593810cSYasunari Takiguchi c->transmission_mode = TRANSMISSION_MODE_2K;
16349593810cSYasunari Takiguchi break;
16359593810cSYasunari Takiguchi case CXD2880_DVBT2_M8K:
16369593810cSYasunari Takiguchi c->transmission_mode = TRANSMISSION_MODE_8K;
16379593810cSYasunari Takiguchi break;
16389593810cSYasunari Takiguchi case CXD2880_DVBT2_M4K:
16399593810cSYasunari Takiguchi c->transmission_mode = TRANSMISSION_MODE_4K;
16409593810cSYasunari Takiguchi break;
16419593810cSYasunari Takiguchi case CXD2880_DVBT2_M1K:
16429593810cSYasunari Takiguchi c->transmission_mode = TRANSMISSION_MODE_1K;
16439593810cSYasunari Takiguchi break;
16449593810cSYasunari Takiguchi case CXD2880_DVBT2_M16K:
16459593810cSYasunari Takiguchi c->transmission_mode = TRANSMISSION_MODE_16K;
16469593810cSYasunari Takiguchi break;
16479593810cSYasunari Takiguchi case CXD2880_DVBT2_M32K:
16489593810cSYasunari Takiguchi c->transmission_mode = TRANSMISSION_MODE_32K;
16499593810cSYasunari Takiguchi break;
16509593810cSYasunari Takiguchi default:
16519593810cSYasunari Takiguchi c->transmission_mode = TRANSMISSION_MODE_2K;
16529593810cSYasunari Takiguchi pr_debug("L1Pre fft_mode is invalid %d\n",
16539593810cSYasunari Takiguchi l1pre.fft_mode);
16549593810cSYasunari Takiguchi break;
16559593810cSYasunari Takiguchi }
16569593810cSYasunari Takiguchi switch (l1pre.gi) {
16579593810cSYasunari Takiguchi case CXD2880_DVBT2_G1_32:
16589593810cSYasunari Takiguchi c->guard_interval = GUARD_INTERVAL_1_32;
16599593810cSYasunari Takiguchi break;
16609593810cSYasunari Takiguchi case CXD2880_DVBT2_G1_16:
16619593810cSYasunari Takiguchi c->guard_interval = GUARD_INTERVAL_1_16;
16629593810cSYasunari Takiguchi break;
16639593810cSYasunari Takiguchi case CXD2880_DVBT2_G1_8:
16649593810cSYasunari Takiguchi c->guard_interval = GUARD_INTERVAL_1_8;
16659593810cSYasunari Takiguchi break;
16669593810cSYasunari Takiguchi case CXD2880_DVBT2_G1_4:
16679593810cSYasunari Takiguchi c->guard_interval = GUARD_INTERVAL_1_4;
16689593810cSYasunari Takiguchi break;
16699593810cSYasunari Takiguchi case CXD2880_DVBT2_G1_128:
16709593810cSYasunari Takiguchi c->guard_interval = GUARD_INTERVAL_1_128;
16719593810cSYasunari Takiguchi break;
16729593810cSYasunari Takiguchi case CXD2880_DVBT2_G19_128:
16739593810cSYasunari Takiguchi c->guard_interval = GUARD_INTERVAL_19_128;
16749593810cSYasunari Takiguchi break;
16759593810cSYasunari Takiguchi case CXD2880_DVBT2_G19_256:
16769593810cSYasunari Takiguchi c->guard_interval = GUARD_INTERVAL_19_256;
16779593810cSYasunari Takiguchi break;
16789593810cSYasunari Takiguchi default:
16799593810cSYasunari Takiguchi c->guard_interval = GUARD_INTERVAL_1_32;
16809593810cSYasunari Takiguchi pr_debug("L1Pre guard interval is invalid %d\n",
16819593810cSYasunari Takiguchi l1pre.gi);
16829593810cSYasunari Takiguchi break;
16839593810cSYasunari Takiguchi }
16849593810cSYasunari Takiguchi } else {
16859593810cSYasunari Takiguchi c->transmission_mode = TRANSMISSION_MODE_2K;
16869593810cSYasunari Takiguchi c->guard_interval = GUARD_INTERVAL_1_32;
16879593810cSYasunari Takiguchi pr_debug("L1Pre err %d\n", ret);
16889593810cSYasunari Takiguchi }
16899593810cSYasunari Takiguchi
16909593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
16919593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt2_mon_code_rate(&priv->tnrdmd,
16929593810cSYasunari Takiguchi CXD2880_DVBT2_PLP_DATA,
16939593810cSYasunari Takiguchi &coderate);
16949593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
16959593810cSYasunari Takiguchi if (!ret) {
16969593810cSYasunari Takiguchi switch (coderate) {
16979593810cSYasunari Takiguchi case CXD2880_DVBT2_R1_2:
16989593810cSYasunari Takiguchi c->fec_inner = FEC_1_2;
16999593810cSYasunari Takiguchi break;
17009593810cSYasunari Takiguchi case CXD2880_DVBT2_R3_5:
17019593810cSYasunari Takiguchi c->fec_inner = FEC_3_5;
17029593810cSYasunari Takiguchi break;
17039593810cSYasunari Takiguchi case CXD2880_DVBT2_R2_3:
17049593810cSYasunari Takiguchi c->fec_inner = FEC_2_3;
17059593810cSYasunari Takiguchi break;
17069593810cSYasunari Takiguchi case CXD2880_DVBT2_R3_4:
17079593810cSYasunari Takiguchi c->fec_inner = FEC_3_4;
17089593810cSYasunari Takiguchi break;
17099593810cSYasunari Takiguchi case CXD2880_DVBT2_R4_5:
17109593810cSYasunari Takiguchi c->fec_inner = FEC_4_5;
17119593810cSYasunari Takiguchi break;
17129593810cSYasunari Takiguchi case CXD2880_DVBT2_R5_6:
17139593810cSYasunari Takiguchi c->fec_inner = FEC_5_6;
17149593810cSYasunari Takiguchi break;
17159593810cSYasunari Takiguchi default:
17169593810cSYasunari Takiguchi c->fec_inner = FEC_NONE;
17179593810cSYasunari Takiguchi pr_debug("CodeRate is invalid %d\n", coderate);
17189593810cSYasunari Takiguchi break;
17199593810cSYasunari Takiguchi }
17209593810cSYasunari Takiguchi } else {
17219593810cSYasunari Takiguchi c->fec_inner = FEC_NONE;
17229593810cSYasunari Takiguchi pr_debug("CodeRate %d\n", ret);
17239593810cSYasunari Takiguchi }
17249593810cSYasunari Takiguchi
17259593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
17269593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt2_mon_qam(&priv->tnrdmd,
17279593810cSYasunari Takiguchi CXD2880_DVBT2_PLP_DATA,
17289593810cSYasunari Takiguchi &qam);
17299593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
17309593810cSYasunari Takiguchi if (!ret) {
17319593810cSYasunari Takiguchi switch (qam) {
17329593810cSYasunari Takiguchi case CXD2880_DVBT2_QPSK:
17339593810cSYasunari Takiguchi c->modulation = QPSK;
17349593810cSYasunari Takiguchi break;
17359593810cSYasunari Takiguchi case CXD2880_DVBT2_QAM16:
17369593810cSYasunari Takiguchi c->modulation = QAM_16;
17379593810cSYasunari Takiguchi break;
17389593810cSYasunari Takiguchi case CXD2880_DVBT2_QAM64:
17399593810cSYasunari Takiguchi c->modulation = QAM_64;
17409593810cSYasunari Takiguchi break;
17419593810cSYasunari Takiguchi case CXD2880_DVBT2_QAM256:
17429593810cSYasunari Takiguchi c->modulation = QAM_256;
17439593810cSYasunari Takiguchi break;
17449593810cSYasunari Takiguchi default:
17459593810cSYasunari Takiguchi c->modulation = QPSK;
17469593810cSYasunari Takiguchi pr_debug("QAM is invalid %d\n", qam);
17479593810cSYasunari Takiguchi break;
17489593810cSYasunari Takiguchi }
17499593810cSYasunari Takiguchi } else {
17509593810cSYasunari Takiguchi c->modulation = QPSK;
17519593810cSYasunari Takiguchi pr_debug("QAM %d\n", ret);
17529593810cSYasunari Takiguchi }
17539593810cSYasunari Takiguchi
17549593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
17559593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(&priv->tnrdmd, &sense);
17569593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
17579593810cSYasunari Takiguchi if (!ret) {
17589593810cSYasunari Takiguchi switch (sense) {
17599593810cSYasunari Takiguchi case CXD2880_TNRDMD_SPECTRUM_NORMAL:
17609593810cSYasunari Takiguchi c->inversion = INVERSION_OFF;
17619593810cSYasunari Takiguchi break;
17629593810cSYasunari Takiguchi case CXD2880_TNRDMD_SPECTRUM_INV:
17639593810cSYasunari Takiguchi c->inversion = INVERSION_ON;
17649593810cSYasunari Takiguchi break;
17659593810cSYasunari Takiguchi default:
17669593810cSYasunari Takiguchi c->inversion = INVERSION_OFF;
17679593810cSYasunari Takiguchi pr_debug("spectrum sense is invalid %d\n", sense);
17689593810cSYasunari Takiguchi break;
17699593810cSYasunari Takiguchi }
17709593810cSYasunari Takiguchi } else {
17719593810cSYasunari Takiguchi c->inversion = INVERSION_OFF;
17729593810cSYasunari Takiguchi pr_debug("SpectrumSense %d\n", ret);
17739593810cSYasunari Takiguchi }
17749593810cSYasunari Takiguchi
17759593810cSYasunari Takiguchi mutex_lock(priv->spi_mutex);
17769593810cSYasunari Takiguchi ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength);
17779593810cSYasunari Takiguchi mutex_unlock(priv->spi_mutex);
17789593810cSYasunari Takiguchi if (!ret) {
17799593810cSYasunari Takiguchi c->strength.len = 1;
17809593810cSYasunari Takiguchi c->strength.stat[0].scale = FE_SCALE_DECIBEL;
17819593810cSYasunari Takiguchi c->strength.stat[0].svalue = strength;
17829593810cSYasunari Takiguchi } else {
17839593810cSYasunari Takiguchi c->strength.len = 1;
17849593810cSYasunari Takiguchi c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
17859593810cSYasunari Takiguchi pr_debug("mon_rf_lvl %d\n", ret);
17869593810cSYasunari Takiguchi }
17879593810cSYasunari Takiguchi
17889593810cSYasunari Takiguchi ret = cxd2880_read_snr(fe, &snr);
17899593810cSYasunari Takiguchi if (!ret) {
17909593810cSYasunari Takiguchi c->cnr.len = 1;
17919593810cSYasunari Takiguchi c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
17929593810cSYasunari Takiguchi c->cnr.stat[0].svalue = snr;
17939593810cSYasunari Takiguchi } else {
17949593810cSYasunari Takiguchi c->cnr.len = 1;
17959593810cSYasunari Takiguchi c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
17969593810cSYasunari Takiguchi pr_debug("read_snr %d\n", ret);
17979593810cSYasunari Takiguchi }
17989593810cSYasunari Takiguchi
17999593810cSYasunari Takiguchi return 0;
18009593810cSYasunari Takiguchi }
18019593810cSYasunari Takiguchi
cxd2880_get_frontend(struct dvb_frontend * fe,struct dtv_frontend_properties * props)18029593810cSYasunari Takiguchi static int cxd2880_get_frontend(struct dvb_frontend *fe,
18039593810cSYasunari Takiguchi struct dtv_frontend_properties *props)
18049593810cSYasunari Takiguchi {
18059593810cSYasunari Takiguchi int ret;
18069593810cSYasunari Takiguchi
18079593810cSYasunari Takiguchi if (!fe || !props) {
18089593810cSYasunari Takiguchi pr_err("invalid arg.");
18099593810cSYasunari Takiguchi return -EINVAL;
18109593810cSYasunari Takiguchi }
18119593810cSYasunari Takiguchi
18129593810cSYasunari Takiguchi pr_debug("system=%d\n", fe->dtv_property_cache.delivery_system);
18139593810cSYasunari Takiguchi switch (fe->dtv_property_cache.delivery_system) {
18149593810cSYasunari Takiguchi case SYS_DVBT:
18159593810cSYasunari Takiguchi ret = cxd2880_get_frontend_t(fe, props);
18169593810cSYasunari Takiguchi break;
18179593810cSYasunari Takiguchi case SYS_DVBT2:
18189593810cSYasunari Takiguchi ret = cxd2880_get_frontend_t2(fe, props);
18199593810cSYasunari Takiguchi break;
18209593810cSYasunari Takiguchi default:
18219593810cSYasunari Takiguchi ret = -EINVAL;
18229593810cSYasunari Takiguchi break;
18239593810cSYasunari Takiguchi }
18249593810cSYasunari Takiguchi
18259593810cSYasunari Takiguchi return ret;
18269593810cSYasunari Takiguchi }
18279593810cSYasunari Takiguchi
cxd2880_get_frontend_algo(struct dvb_frontend * fe)18289593810cSYasunari Takiguchi static enum dvbfe_algo cxd2880_get_frontend_algo(struct dvb_frontend *fe)
18299593810cSYasunari Takiguchi {
18309593810cSYasunari Takiguchi return DVBFE_ALGO_HW;
18319593810cSYasunari Takiguchi }
18329593810cSYasunari Takiguchi
18339593810cSYasunari Takiguchi static struct dvb_frontend_ops cxd2880_dvbt_t2_ops = {
18349593810cSYasunari Takiguchi .info = {
18359593810cSYasunari Takiguchi .name = "Sony CXD2880",
1836f1b1eabfSMauro Carvalho Chehab .frequency_min_hz = 174 * MHz,
1837f1b1eabfSMauro Carvalho Chehab .frequency_max_hz = 862 * MHz,
1838f1b1eabfSMauro Carvalho Chehab .frequency_stepsize_hz = 1 * kHz,
18399593810cSYasunari Takiguchi .caps = FE_CAN_INVERSION_AUTO |
18409593810cSYasunari Takiguchi FE_CAN_FEC_1_2 |
18419593810cSYasunari Takiguchi FE_CAN_FEC_2_3 |
18429593810cSYasunari Takiguchi FE_CAN_FEC_3_4 |
18439593810cSYasunari Takiguchi FE_CAN_FEC_4_5 |
18449593810cSYasunari Takiguchi FE_CAN_FEC_5_6 |
18459593810cSYasunari Takiguchi FE_CAN_FEC_7_8 |
18469593810cSYasunari Takiguchi FE_CAN_FEC_AUTO |
18479593810cSYasunari Takiguchi FE_CAN_QPSK |
18489593810cSYasunari Takiguchi FE_CAN_QAM_16 |
18499593810cSYasunari Takiguchi FE_CAN_QAM_32 |
18509593810cSYasunari Takiguchi FE_CAN_QAM_64 |
18519593810cSYasunari Takiguchi FE_CAN_QAM_128 |
18529593810cSYasunari Takiguchi FE_CAN_QAM_256 |
18539593810cSYasunari Takiguchi FE_CAN_QAM_AUTO |
18549593810cSYasunari Takiguchi FE_CAN_TRANSMISSION_MODE_AUTO |
18559593810cSYasunari Takiguchi FE_CAN_GUARD_INTERVAL_AUTO |
18569593810cSYasunari Takiguchi FE_CAN_2G_MODULATION |
18579593810cSYasunari Takiguchi FE_CAN_RECOVER |
18589593810cSYasunari Takiguchi FE_CAN_MUTE_TS,
18599593810cSYasunari Takiguchi },
18609593810cSYasunari Takiguchi .delsys = { SYS_DVBT, SYS_DVBT2 },
18619593810cSYasunari Takiguchi
18629593810cSYasunari Takiguchi .release = cxd2880_release,
18639593810cSYasunari Takiguchi .init = cxd2880_init,
18649593810cSYasunari Takiguchi .sleep = cxd2880_sleep,
18659593810cSYasunari Takiguchi .tune = cxd2880_tune,
18669593810cSYasunari Takiguchi .set_frontend = cxd2880_set_frontend,
18679593810cSYasunari Takiguchi .get_frontend = cxd2880_get_frontend,
18689593810cSYasunari Takiguchi .read_status = cxd2880_read_status,
18699593810cSYasunari Takiguchi .read_ber = cxd2880_read_ber,
18709593810cSYasunari Takiguchi .read_signal_strength = cxd2880_read_signal_strength,
18719593810cSYasunari Takiguchi .read_snr = cxd2880_read_snr,
18729593810cSYasunari Takiguchi .read_ucblocks = cxd2880_read_ucblocks,
18739593810cSYasunari Takiguchi .get_frontend_algo = cxd2880_get_frontend_algo,
18749593810cSYasunari Takiguchi };
18759593810cSYasunari Takiguchi
cxd2880_attach(struct dvb_frontend * fe,struct cxd2880_config * cfg)18769593810cSYasunari Takiguchi struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
18779593810cSYasunari Takiguchi struct cxd2880_config *cfg)
18789593810cSYasunari Takiguchi {
18799593810cSYasunari Takiguchi int ret;
18809593810cSYasunari Takiguchi enum cxd2880_tnrdmd_chip_id chipid =
18819593810cSYasunari Takiguchi CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
18829593810cSYasunari Takiguchi static struct cxd2880_priv *priv;
18839593810cSYasunari Takiguchi u8 data = 0;
18849593810cSYasunari Takiguchi
18859593810cSYasunari Takiguchi if (!fe) {
18869593810cSYasunari Takiguchi pr_err("invalid arg.\n");
18879593810cSYasunari Takiguchi return NULL;
18889593810cSYasunari Takiguchi }
18899593810cSYasunari Takiguchi
18909593810cSYasunari Takiguchi priv = kzalloc(sizeof(struct cxd2880_priv), GFP_KERNEL);
18919593810cSYasunari Takiguchi if (!priv)
18929593810cSYasunari Takiguchi return NULL;
18939593810cSYasunari Takiguchi
18949593810cSYasunari Takiguchi priv->spi = cfg->spi;
18959593810cSYasunari Takiguchi priv->spi_mutex = cfg->spi_mutex;
18969593810cSYasunari Takiguchi priv->spi_device.spi = cfg->spi;
18979593810cSYasunari Takiguchi
18989593810cSYasunari Takiguchi memcpy(&fe->ops, &cxd2880_dvbt_t2_ops,
18999593810cSYasunari Takiguchi sizeof(struct dvb_frontend_ops));
19009593810cSYasunari Takiguchi
19019593810cSYasunari Takiguchi ret = cxd2880_spi_device_initialize(&priv->spi_device,
19029593810cSYasunari Takiguchi CXD2880_SPI_MODE_0,
19039593810cSYasunari Takiguchi 55000000);
19049593810cSYasunari Takiguchi if (ret) {
19059593810cSYasunari Takiguchi pr_err("spi_device_initialize failed. %d\n", ret);
19069593810cSYasunari Takiguchi kfree(priv);
19079593810cSYasunari Takiguchi return NULL;
19089593810cSYasunari Takiguchi }
19099593810cSYasunari Takiguchi
19109593810cSYasunari Takiguchi ret = cxd2880_spi_device_create_spi(&priv->cxd2880_spi,
19119593810cSYasunari Takiguchi &priv->spi_device);
19129593810cSYasunari Takiguchi if (ret) {
19139593810cSYasunari Takiguchi pr_err("spi_device_create_spi failed. %d\n", ret);
19149593810cSYasunari Takiguchi kfree(priv);
19159593810cSYasunari Takiguchi return NULL;
19169593810cSYasunari Takiguchi }
19179593810cSYasunari Takiguchi
19189593810cSYasunari Takiguchi ret = cxd2880_io_spi_create(&priv->regio, &priv->cxd2880_spi, 0);
19199593810cSYasunari Takiguchi if (ret) {
19209593810cSYasunari Takiguchi pr_err("io_spi_create failed. %d\n", ret);
19219593810cSYasunari Takiguchi kfree(priv);
19229593810cSYasunari Takiguchi return NULL;
19239593810cSYasunari Takiguchi }
19249593810cSYasunari Takiguchi ret = priv->regio.write_reg(&priv->regio,
19259593810cSYasunari Takiguchi CXD2880_IO_TGT_SYS, 0x00, 0x00);
19269593810cSYasunari Takiguchi if (ret) {
19279593810cSYasunari Takiguchi pr_err("set bank to 0x00 failed.\n");
19289593810cSYasunari Takiguchi kfree(priv);
19299593810cSYasunari Takiguchi return NULL;
19309593810cSYasunari Takiguchi }
19319593810cSYasunari Takiguchi ret = priv->regio.read_regs(&priv->regio,
19329593810cSYasunari Takiguchi CXD2880_IO_TGT_SYS, 0xfd, &data, 1);
19339593810cSYasunari Takiguchi if (ret) {
19349593810cSYasunari Takiguchi pr_err("read chip id failed.\n");
19359593810cSYasunari Takiguchi kfree(priv);
19369593810cSYasunari Takiguchi return NULL;
19379593810cSYasunari Takiguchi }
19389593810cSYasunari Takiguchi
19399593810cSYasunari Takiguchi chipid = (enum cxd2880_tnrdmd_chip_id)data;
19409593810cSYasunari Takiguchi if (chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X &&
19419593810cSYasunari Takiguchi chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11) {
19429593810cSYasunari Takiguchi pr_err("chip id invalid.\n");
19439593810cSYasunari Takiguchi kfree(priv);
19449593810cSYasunari Takiguchi return NULL;
19459593810cSYasunari Takiguchi }
19469593810cSYasunari Takiguchi
19479593810cSYasunari Takiguchi fe->demodulator_priv = priv;
19489593810cSYasunari Takiguchi pr_info("CXD2880 driver version: Ver %s\n",
19499593810cSYasunari Takiguchi CXD2880_TNRDMD_DRIVER_VERSION);
19509593810cSYasunari Takiguchi
19519593810cSYasunari Takiguchi return fe;
19529593810cSYasunari Takiguchi }
1953*86495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(cxd2880_attach);
19549593810cSYasunari Takiguchi
19559593810cSYasunari Takiguchi MODULE_DESCRIPTION("Sony CXD2880 DVB-T2/T tuner + demod driver");
19569593810cSYasunari Takiguchi MODULE_AUTHOR("Sony Semiconductor Solutions Corporation");
19579593810cSYasunari Takiguchi MODULE_LICENSE("GPL v2");
1958