Path: blob/master/drivers/media/dvb/frontends/cxd2820r_t2.c
15112 views
/*1* Sony CXD2820R demodulator driver2*3* Copyright (C) 2010 Antti Palosaari <[email protected]>4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License along16* with this program; if not, write to the Free Software Foundation, Inc.,17* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.18*/192021#include "cxd2820r_priv.h"2223int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,24struct dvb_frontend_parameters *params)25{26struct cxd2820r_priv *priv = fe->demodulator_priv;27struct dtv_frontend_properties *c = &fe->dtv_property_cache;28int ret, i;29u32 if_khz, if_ctl;30u64 num;31u8 buf[3], bw_param;32u8 bw_params1[][5] = {33{ 0x1c, 0xb3, 0x33, 0x33, 0x33 }, /* 5 MHz */34{ 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */35{ 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */36{ 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */37};38struct reg_val_mask tab[] = {39{ 0x00080, 0x02, 0xff },40{ 0x00081, 0x20, 0xff },41{ 0x00085, 0x07, 0xff },42{ 0x00088, 0x01, 0xff },43{ 0x02069, 0x01, 0xff },4445{ 0x0207f, 0x2a, 0xff },46{ 0x02082, 0x0a, 0xff },47{ 0x02083, 0x0a, 0xff },48{ 0x020cb, priv->cfg.if_agc_polarity << 6, 0x40 },49{ 0x02070, priv->cfg.ts_mode, 0xff },50{ 0x020b5, priv->cfg.spec_inv << 4, 0x10 },51{ 0x02567, 0x07, 0x0f },52{ 0x02569, 0x03, 0x03 },53{ 0x02595, 0x1a, 0xff },54{ 0x02596, 0x50, 0xff },55{ 0x02a8c, 0x00, 0xff },56{ 0x02a8d, 0x34, 0xff },57{ 0x02a45, 0x06, 0x07 },58{ 0x03f10, 0x0d, 0xff },59{ 0x03f11, 0x02, 0xff },60{ 0x03f12, 0x01, 0xff },61{ 0x03f23, 0x2c, 0xff },62{ 0x03f51, 0x13, 0xff },63{ 0x03f52, 0x01, 0xff },64{ 0x03f53, 0x00, 0xff },65{ 0x027e6, 0x14, 0xff },66{ 0x02786, 0x02, 0x07 },67{ 0x02787, 0x40, 0xe0 },68{ 0x027ef, 0x10, 0x18 },69};7071dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);7273/* update GPIOs */74ret = cxd2820r_gpio(fe);75if (ret)76goto error;7778/* program tuner */79if (fe->ops.tuner_ops.set_params)80fe->ops.tuner_ops.set_params(fe, params);8182if (priv->delivery_system != SYS_DVBT2) {83for (i = 0; i < ARRAY_SIZE(tab); i++) {84ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,85tab[i].val, tab[i].mask);86if (ret)87goto error;88}89}9091priv->delivery_system = SYS_DVBT2;9293switch (c->bandwidth_hz) {94case 5000000:95if_khz = priv->cfg.if_dvbt2_5;96i = 0;97bw_param = 3;98break;99case 6000000:100if_khz = priv->cfg.if_dvbt2_6;101i = 1;102bw_param = 2;103break;104case 7000000:105if_khz = priv->cfg.if_dvbt2_7;106i = 2;107bw_param = 1;108break;109case 8000000:110if_khz = priv->cfg.if_dvbt2_8;111i = 3;112bw_param = 0;113break;114default:115return -EINVAL;116}117118num = if_khz;119num *= 0x1000000;120if_ctl = cxd2820r_div_u64_round_closest(num, 41000);121buf[0] = ((if_ctl >> 16) & 0xff);122buf[1] = ((if_ctl >> 8) & 0xff);123buf[2] = ((if_ctl >> 0) & 0xff);124125ret = cxd2820r_wr_regs(priv, 0x020b6, buf, 3);126if (ret)127goto error;128129ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[i], 5);130if (ret)131goto error;132133ret = cxd2820r_wr_reg_mask(priv, 0x020d7, bw_param << 6, 0xc0);134if (ret)135goto error;136137ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);138if (ret)139goto error;140141ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);142if (ret)143goto error;144145return ret;146error:147dbg("%s: failed:%d", __func__, ret);148return ret;149150}151152int cxd2820r_get_frontend_t2(struct dvb_frontend *fe,153struct dvb_frontend_parameters *p)154{155struct cxd2820r_priv *priv = fe->demodulator_priv;156struct dtv_frontend_properties *c = &fe->dtv_property_cache;157int ret;158u8 buf[2];159160ret = cxd2820r_rd_regs(priv, 0x0205c, buf, 2);161if (ret)162goto error;163164switch ((buf[0] >> 0) & 0x07) {165case 0:166c->transmission_mode = TRANSMISSION_MODE_2K;167break;168case 1:169c->transmission_mode = TRANSMISSION_MODE_8K;170break;171case 2:172c->transmission_mode = TRANSMISSION_MODE_4K;173break;174case 3:175c->transmission_mode = TRANSMISSION_MODE_1K;176break;177case 4:178c->transmission_mode = TRANSMISSION_MODE_16K;179break;180case 5:181c->transmission_mode = TRANSMISSION_MODE_32K;182break;183}184185switch ((buf[1] >> 4) & 0x07) {186case 0:187c->guard_interval = GUARD_INTERVAL_1_32;188break;189case 1:190c->guard_interval = GUARD_INTERVAL_1_16;191break;192case 2:193c->guard_interval = GUARD_INTERVAL_1_8;194break;195case 3:196c->guard_interval = GUARD_INTERVAL_1_4;197break;198case 4:199c->guard_interval = GUARD_INTERVAL_1_128;200break;201case 5:202c->guard_interval = GUARD_INTERVAL_19_128;203break;204case 6:205c->guard_interval = GUARD_INTERVAL_19_256;206break;207}208209ret = cxd2820r_rd_regs(priv, 0x0225b, buf, 2);210if (ret)211goto error;212213switch ((buf[0] >> 0) & 0x07) {214case 0:215c->fec_inner = FEC_1_2;216break;217case 1:218c->fec_inner = FEC_3_5;219break;220case 2:221c->fec_inner = FEC_2_3;222break;223case 3:224c->fec_inner = FEC_3_4;225break;226case 4:227c->fec_inner = FEC_4_5;228break;229case 5:230c->fec_inner = FEC_5_6;231break;232}233234switch ((buf[1] >> 0) & 0x07) {235case 0:236c->modulation = QPSK;237break;238case 1:239c->modulation = QAM_16;240break;241case 2:242c->modulation = QAM_64;243break;244case 3:245c->modulation = QAM_256;246break;247}248249ret = cxd2820r_rd_reg(priv, 0x020b5, &buf[0]);250if (ret)251goto error;252253switch ((buf[0] >> 4) & 0x01) {254case 0:255c->inversion = INVERSION_OFF;256break;257case 1:258c->inversion = INVERSION_ON;259break;260}261262return ret;263error:264dbg("%s: failed:%d", __func__, ret);265return ret;266}267268int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status)269{270struct cxd2820r_priv *priv = fe->demodulator_priv;271int ret;272u8 buf[1];273*status = 0;274275ret = cxd2820r_rd_reg(priv, 0x02010 , &buf[0]);276if (ret)277goto error;278279if ((buf[0] & 0x07) == 6) {280if (((buf[0] >> 5) & 0x01) == 1) {281*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |282FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;283} else {284*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |285FE_HAS_VITERBI | FE_HAS_SYNC;286}287}288289dbg("%s: lock=%02x", __func__, buf[0]);290291return ret;292error:293dbg("%s: failed:%d", __func__, ret);294return ret;295}296297int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber)298{299struct cxd2820r_priv *priv = fe->demodulator_priv;300int ret;301u8 buf[4];302unsigned int errbits;303*ber = 0;304/* FIXME: correct calculation */305306ret = cxd2820r_rd_regs(priv, 0x02039, buf, sizeof(buf));307if (ret)308goto error;309310if ((buf[0] >> 4) & 0x01) {311errbits = (buf[0] & 0x0f) << 24 | buf[1] << 16 |312buf[2] << 8 | buf[3];313314if (errbits)315*ber = errbits * 64 / 16588800;316}317318return ret;319error:320dbg("%s: failed:%d", __func__, ret);321return ret;322}323324int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe,325u16 *strength)326{327struct cxd2820r_priv *priv = fe->demodulator_priv;328int ret;329u8 buf[2];330u16 tmp;331332ret = cxd2820r_rd_regs(priv, 0x02026, buf, sizeof(buf));333if (ret)334goto error;335336tmp = (buf[0] & 0x0f) << 8 | buf[1];337tmp = ~tmp & 0x0fff;338339/* scale value to 0x0000-0xffff from 0x0000-0x0fff */340*strength = tmp * 0xffff / 0x0fff;341342return ret;343error:344dbg("%s: failed:%d", __func__, ret);345return ret;346}347348int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr)349{350struct cxd2820r_priv *priv = fe->demodulator_priv;351int ret;352u8 buf[2];353u16 tmp;354/* report SNR in dB * 10 */355356ret = cxd2820r_rd_regs(priv, 0x02028, buf, sizeof(buf));357if (ret)358goto error;359360tmp = (buf[0] & 0x0f) << 8 | buf[1];361#define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */362if (tmp)363*snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24)364/ 100);365else366*snr = 0;367368dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp);369370return ret;371error:372dbg("%s: failed:%d", __func__, ret);373return ret;374}375376int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks)377{378*ucblocks = 0;379/* no way to read ? */380return 0;381}382383int cxd2820r_sleep_t2(struct dvb_frontend *fe)384{385struct cxd2820r_priv *priv = fe->demodulator_priv;386int ret, i;387struct reg_val_mask tab[] = {388{ 0x000ff, 0x1f, 0xff },389{ 0x00085, 0x00, 0xff },390{ 0x00088, 0x01, 0xff },391{ 0x02069, 0x00, 0xff },392{ 0x00081, 0x00, 0xff },393{ 0x00080, 0x00, 0xff },394};395396dbg("%s", __func__);397398for (i = 0; i < ARRAY_SIZE(tab); i++) {399ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,400tab[i].mask);401if (ret)402goto error;403}404405priv->delivery_system = SYS_UNDEFINED;406407return ret;408error:409dbg("%s: failed:%d", __func__, ret);410return ret;411}412413int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe,414struct dvb_frontend_tune_settings *s)415{416s->min_delay_ms = 1500;417s->step_size = fe->ops.info.frequency_stepsize * 2;418s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;419420return 0;421}422423424425