linux/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
<<
>>
Prefs
   1/*
   2 *  mxl111sf-demod.c - driver for the MaxLinear MXL111SF DVB-T demodulator
   3 *
   4 *  Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
   5 *
   6 *  This program is free software; you can redistribute it and/or modify
   7 *  it under the terms of the GNU General Public License as published by
   8 *  the Free Software Foundation; either version 2 of the License, or
   9 *  (at your option) any later version.
  10 *
  11 *  This program is distributed in the hope that it will be useful,
  12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *  GNU General Public License for more details.
  15 *
  16 *  You should have received a copy of the GNU General Public License
  17 *  along with this program; if not, write to the Free Software
  18 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19 */
  20
  21#include "mxl111sf-demod.h"
  22#include "mxl111sf-reg.h"
  23
  24/* debug */
  25static int mxl111sf_demod_debug;
  26module_param_named(debug, mxl111sf_demod_debug, int, 0644);
  27MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
  28
  29#define mxl_dbg(fmt, arg...) \
  30        if (mxl111sf_demod_debug) \
  31                mxl_printk(KERN_DEBUG, fmt, ##arg)
  32
  33/* ------------------------------------------------------------------------ */
  34
  35struct mxl111sf_demod_state {
  36        struct mxl111sf_state *mxl_state;
  37
  38        const struct mxl111sf_demod_config *cfg;
  39
  40        struct dvb_frontend fe;
  41};
  42
  43/* ------------------------------------------------------------------------ */
  44
  45static int mxl111sf_demod_read_reg(struct mxl111sf_demod_state *state,
  46                                   u8 addr, u8 *data)
  47{
  48        return (state->cfg->read_reg) ?
  49                state->cfg->read_reg(state->mxl_state, addr, data) :
  50                -EINVAL;
  51}
  52
  53static int mxl111sf_demod_write_reg(struct mxl111sf_demod_state *state,
  54                                    u8 addr, u8 data)
  55{
  56        return (state->cfg->write_reg) ?
  57                state->cfg->write_reg(state->mxl_state, addr, data) :
  58                -EINVAL;
  59}
  60
  61static
  62int mxl111sf_demod_program_regs(struct mxl111sf_demod_state *state,
  63                                struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
  64{
  65        return (state->cfg->program_regs) ?
  66                state->cfg->program_regs(state->mxl_state, ctrl_reg_info) :
  67                -EINVAL;
  68}
  69
  70/* ------------------------------------------------------------------------ */
  71/* TPS */
  72
  73static
  74int mxl1x1sf_demod_get_tps_code_rate(struct mxl111sf_demod_state *state,
  75                                     enum fe_code_rate *code_rate)
  76{
  77        u8 val;
  78        int ret = mxl111sf_demod_read_reg(state, V6_CODE_RATE_TPS_REG, &val);
  79        /* bit<2:0> - 000:1/2, 001:2/3, 010:3/4, 011:5/6, 100:7/8 */
  80        if (mxl_fail(ret))
  81                goto fail;
  82
  83        switch (val & V6_CODE_RATE_TPS_MASK) {
  84        case 0:
  85                *code_rate = FEC_1_2;
  86                break;
  87        case 1:
  88                *code_rate = FEC_2_3;
  89                break;
  90        case 2:
  91                *code_rate = FEC_3_4;
  92                break;
  93        case 3:
  94                *code_rate = FEC_5_6;
  95                break;
  96        case 4:
  97                *code_rate = FEC_7_8;
  98                break;
  99        }
 100fail:
 101        return ret;
 102}
 103
 104static
 105int mxl1x1sf_demod_get_tps_modulation(struct mxl111sf_demod_state *state,
 106                                      enum fe_modulation *modulation)
 107{
 108        u8 val;
 109        int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val);
 110        /* Constellation, 00 : QPSK, 01 : 16QAM, 10:64QAM */
 111        if (mxl_fail(ret))
 112                goto fail;
 113
 114        switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) {
 115        case 0:
 116                *modulation = QPSK;
 117                break;
 118        case 1:
 119                *modulation = QAM_16;
 120                break;
 121        case 2:
 122                *modulation = QAM_64;
 123                break;
 124        }
 125fail:
 126        return ret;
 127}
 128
 129static
 130int mxl1x1sf_demod_get_tps_guard_fft_mode(struct mxl111sf_demod_state *state,
 131                                          enum fe_transmit_mode *fft_mode)
 132{
 133        u8 val;
 134        int ret = mxl111sf_demod_read_reg(state, V6_MODE_TPS_REG, &val);
 135        /* FFT Mode, 00:2K, 01:8K, 10:4K */
 136        if (mxl_fail(ret))
 137                goto fail;
 138
 139        switch ((val & V6_PARAM_FFT_MODE_MASK) >> 2) {
 140        case 0:
 141                *fft_mode = TRANSMISSION_MODE_2K;
 142                break;
 143        case 1:
 144                *fft_mode = TRANSMISSION_MODE_8K;
 145                break;
 146        case 2:
 147                *fft_mode = TRANSMISSION_MODE_4K;
 148                break;
 149        }
 150fail:
 151        return ret;
 152}
 153
 154static
 155int mxl1x1sf_demod_get_tps_guard_interval(struct mxl111sf_demod_state *state,
 156                                          enum fe_guard_interval *guard)
 157{
 158        u8 val;
 159        int ret = mxl111sf_demod_read_reg(state, V6_CP_TPS_REG, &val);
 160        /* 00:1/32, 01:1/16, 10:1/8, 11:1/4 */
 161        if (mxl_fail(ret))
 162                goto fail;
 163
 164        switch ((val & V6_PARAM_GI_MASK) >> 4) {
 165        case 0:
 166                *guard = GUARD_INTERVAL_1_32;
 167                break;
 168        case 1:
 169                *guard = GUARD_INTERVAL_1_16;
 170                break;
 171        case 2:
 172                *guard = GUARD_INTERVAL_1_8;
 173                break;
 174        case 3:
 175                *guard = GUARD_INTERVAL_1_4;
 176                break;
 177        }
 178fail:
 179        return ret;
 180}
 181
 182static
 183int mxl1x1sf_demod_get_tps_hierarchy(struct mxl111sf_demod_state *state,
 184                                     enum fe_hierarchy *hierarchy)
 185{
 186        u8 val;
 187        int ret = mxl111sf_demod_read_reg(state, V6_TPS_HIERACHY_REG, &val);
 188        /* bit<6:4> - 000:Non hierarchy, 001:1, 010:2, 011:4 */
 189        if (mxl_fail(ret))
 190                goto fail;
 191
 192        switch ((val & V6_TPS_HIERARCHY_INFO_MASK) >> 6) {
 193        case 0:
 194                *hierarchy = HIERARCHY_NONE;
 195                break;
 196        case 1:
 197                *hierarchy = HIERARCHY_1;
 198                break;
 199        case 2:
 200                *hierarchy = HIERARCHY_2;
 201                break;
 202        case 3:
 203                *hierarchy = HIERARCHY_4;
 204                break;
 205        }
 206fail:
 207        return ret;
 208}
 209
 210/* ------------------------------------------------------------------------ */
 211/* LOCKS */
 212
 213static
 214int mxl1x1sf_demod_get_sync_lock_status(struct mxl111sf_demod_state *state,
 215                                        int *sync_lock)
 216{
 217        u8 val = 0;
 218        int ret = mxl111sf_demod_read_reg(state, V6_SYNC_LOCK_REG, &val);
 219        if (mxl_fail(ret))
 220                goto fail;
 221        *sync_lock = (val & SYNC_LOCK_MASK) >> 4;
 222fail:
 223        return ret;
 224}
 225
 226static
 227int mxl1x1sf_demod_get_rs_lock_status(struct mxl111sf_demod_state *state,
 228                                      int *rs_lock)
 229{
 230        u8 val = 0;
 231        int ret = mxl111sf_demod_read_reg(state, V6_RS_LOCK_DET_REG, &val);
 232        if (mxl_fail(ret))
 233                goto fail;
 234        *rs_lock = (val & RS_LOCK_DET_MASK) >> 3;
 235fail:
 236        return ret;
 237}
 238
 239static
 240int mxl1x1sf_demod_get_tps_lock_status(struct mxl111sf_demod_state *state,
 241                                       int *tps_lock)
 242{
 243        u8 val = 0;
 244        int ret = mxl111sf_demod_read_reg(state, V6_TPS_LOCK_REG, &val);
 245        if (mxl_fail(ret))
 246                goto fail;
 247        *tps_lock = (val & V6_PARAM_TPS_LOCK_MASK) >> 6;
 248fail:
 249        return ret;
 250}
 251
 252static
 253int mxl1x1sf_demod_get_fec_lock_status(struct mxl111sf_demod_state *state,
 254                                       int *fec_lock)
 255{
 256        u8 val = 0;
 257        int ret = mxl111sf_demod_read_reg(state, V6_IRQ_STATUS_REG, &val);
 258        if (mxl_fail(ret))
 259                goto fail;
 260        *fec_lock = (val & IRQ_MASK_FEC_LOCK) >> 4;
 261fail:
 262        return ret;
 263}
 264
 265#if 0
 266static
 267int mxl1x1sf_demod_get_cp_lock_status(struct mxl111sf_demod_state *state,
 268                                      int *cp_lock)
 269{
 270        u8 val = 0;
 271        int ret = mxl111sf_demod_read_reg(state, V6_CP_LOCK_DET_REG, &val);
 272        if (mxl_fail(ret))
 273                goto fail;
 274        *cp_lock = (val & V6_CP_LOCK_DET_MASK) >> 2;
 275fail:
 276        return ret;
 277}
 278#endif
 279
 280static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state)
 281{
 282        return mxl111sf_demod_write_reg(state, 0x0e, 0xff);
 283}
 284
 285/* ------------------------------------------------------------------------ */
 286
 287static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe)
 288{
 289        struct mxl111sf_demod_state *state = fe->demodulator_priv;
 290        int ret = 0;
 291
 292        struct mxl111sf_reg_ctrl_info phy_pll_patch[] = {
 293                {0x00, 0xff, 0x01}, /* change page to 1 */
 294                {0x40, 0xff, 0x05},
 295                {0x40, 0xff, 0x01},
 296                {0x41, 0xff, 0xca},
 297                {0x41, 0xff, 0xc0},
 298                {0x00, 0xff, 0x00}, /* change page to 0 */
 299                {0,    0,    0}
 300        };
 301
 302        mxl_dbg("()");
 303
 304        if (fe->ops.tuner_ops.set_params) {
 305                ret = fe->ops.tuner_ops.set_params(fe);
 306                if (mxl_fail(ret))
 307                        goto fail;
 308                msleep(50);
 309        }
 310        ret = mxl111sf_demod_program_regs(state, phy_pll_patch);
 311        mxl_fail(ret);
 312        msleep(50);
 313        ret = mxl1x1sf_demod_reset_irq_status(state);
 314        mxl_fail(ret);
 315        msleep(100);
 316fail:
 317        return ret;
 318}
 319
 320/* ------------------------------------------------------------------------ */
 321
 322#if 0
 323/* resets TS Packet error count */
 324/* After setting 7th bit of V5_PER_COUNT_RESET_REG, it should be reset to 0. */
 325static
 326int mxl1x1sf_demod_reset_packet_error_count(struct mxl111sf_demod_state *state)
 327{
 328        struct mxl111sf_reg_ctrl_info reset_per_count[] = {
 329                {0x20, 0x01, 0x01},
 330                {0x20, 0x01, 0x00},
 331                {0,    0,    0}
 332        };
 333        return mxl111sf_demod_program_regs(state, reset_per_count);
 334}
 335#endif
 336
 337/* returns TS Packet error count */
 338/* PER Count = FEC_PER_COUNT * (2 ** (FEC_PER_SCALE * 4)) */
 339static int mxl111sf_demod_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 340{
 341        struct mxl111sf_demod_state *state = fe->demodulator_priv;
 342        u32 fec_per_count, fec_per_scale;
 343        u8 val;
 344        int ret;
 345
 346        *ucblocks = 0;
 347
 348        /* FEC_PER_COUNT Register */
 349        ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_COUNT_REG, &val);
 350        if (mxl_fail(ret))
 351                goto fail;
 352
 353        fec_per_count = val;
 354
 355        /* FEC_PER_SCALE Register */
 356        ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_SCALE_REG, &val);
 357        if (mxl_fail(ret))
 358                goto fail;
 359
 360        val &= V6_FEC_PER_SCALE_MASK;
 361        val *= 4;
 362
 363        fec_per_scale = 1 << val;
 364
 365        fec_per_count *= fec_per_scale;
 366
 367        *ucblocks = fec_per_count;
 368fail:
 369        return ret;
 370}
 371
 372#ifdef MXL111SF_DEMOD_ENABLE_CALCULATIONS
 373/* FIXME: leaving this enabled breaks the build on some architectures,
 374 * and we shouldn't have any floating point math in the kernel, anyway.
 375 *
 376 * These macros need to be re-written, but it's harmless to simply
 377 * return zero for now. */
 378#define CALCULATE_BER(avg_errors, count) \
 379        ((u32)(avg_errors * 4)/(count*64*188*8))
 380#define CALCULATE_SNR(data) \
 381        ((u32)((10 * (u32)data / 64) - 2.5))
 382#else
 383#define CALCULATE_BER(avg_errors, count) 0
 384#define CALCULATE_SNR(data) 0
 385#endif
 386
 387static int mxl111sf_demod_read_ber(struct dvb_frontend *fe, u32 *ber)
 388{
 389        struct mxl111sf_demod_state *state = fe->demodulator_priv;
 390        u8 val1, val2, val3;
 391        int ret;
 392
 393        *ber = 0;
 394
 395        ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_LSB_REG, &val1);
 396        if (mxl_fail(ret))
 397                goto fail;
 398        ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_MSB_REG, &val2);
 399        if (mxl_fail(ret))
 400                goto fail;
 401        ret = mxl111sf_demod_read_reg(state, V6_N_ACCUMULATE_REG, &val3);
 402        if (mxl_fail(ret))
 403                goto fail;
 404
 405        *ber = CALCULATE_BER((val1 | (val2 << 8)), val3);
 406fail:
 407        return ret;
 408}
 409
 410static int mxl111sf_demod_calc_snr(struct mxl111sf_demod_state *state,
 411                                   u16 *snr)
 412{
 413        u8 val1, val2;
 414        int ret;
 415
 416        *snr = 0;
 417
 418        ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_LSB_REG, &val1);
 419        if (mxl_fail(ret))
 420                goto fail;
 421        ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_MSB_REG, &val2);
 422        if (mxl_fail(ret))
 423                goto fail;
 424
 425        *snr = CALCULATE_SNR(val1 | ((val2 & 0x03) << 8));
 426fail:
 427        return ret;
 428}
 429
 430static int mxl111sf_demod_read_snr(struct dvb_frontend *fe, u16 *snr)
 431{
 432        struct mxl111sf_demod_state *state = fe->demodulator_priv;
 433
 434        int ret = mxl111sf_demod_calc_snr(state, snr);
 435        if (mxl_fail(ret))
 436                goto fail;
 437
 438        *snr /= 10; /* 0.1 dB */
 439fail:
 440        return ret;
 441}
 442
 443static int mxl111sf_demod_read_status(struct dvb_frontend *fe,
 444                                      enum fe_status *status)
 445{
 446        struct mxl111sf_demod_state *state = fe->demodulator_priv;
 447        int ret, locked, cr_lock, sync_lock, fec_lock;
 448
 449        *status = 0;
 450
 451        ret = mxl1x1sf_demod_get_rs_lock_status(state, &locked);
 452        if (mxl_fail(ret))
 453                goto fail;
 454        ret = mxl1x1sf_demod_get_tps_lock_status(state, &cr_lock);
 455        if (mxl_fail(ret))
 456                goto fail;
 457        ret = mxl1x1sf_demod_get_sync_lock_status(state, &sync_lock);
 458        if (mxl_fail(ret))
 459                goto fail;
 460        ret = mxl1x1sf_demod_get_fec_lock_status(state, &fec_lock);
 461        if (mxl_fail(ret))
 462                goto fail;
 463
 464        if (locked)
 465                *status |= FE_HAS_SIGNAL;
 466        if (cr_lock)
 467                *status |= FE_HAS_CARRIER;
 468        if (sync_lock)
 469                *status |= FE_HAS_SYNC;
 470        if (fec_lock) /* false positives? */
 471                *status |= FE_HAS_VITERBI;
 472
 473        if ((locked) && (cr_lock) && (sync_lock))
 474                *status |= FE_HAS_LOCK;
 475fail:
 476        return ret;
 477}
 478
 479static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe,
 480                                               u16 *signal_strength)
 481{
 482        struct mxl111sf_demod_state *state = fe->demodulator_priv;
 483        enum fe_modulation modulation;
 484        u16 snr;
 485
 486        mxl111sf_demod_calc_snr(state, &snr);
 487        mxl1x1sf_demod_get_tps_modulation(state, &modulation);
 488
 489        switch (modulation) {
 490        case QPSK:
 491                *signal_strength = (snr >= 1300) ?
 492                        min(65535, snr * 44) : snr * 38;
 493                break;
 494        case QAM_16:
 495                *signal_strength = (snr >= 1500) ?
 496                        min(65535, snr * 38) : snr * 33;
 497                break;
 498        case QAM_64:
 499                *signal_strength = (snr >= 2000) ?
 500                        min(65535, snr * 29) : snr * 25;
 501                break;
 502        default:
 503                *signal_strength = 0;
 504                return -EINVAL;
 505        }
 506
 507        return 0;
 508}
 509
 510static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe,
 511                                       struct dtv_frontend_properties *p)
 512{
 513        struct mxl111sf_demod_state *state = fe->demodulator_priv;
 514
 515        mxl_dbg("()");
 516#if 0
 517        p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF;
 518#endif
 519        if (fe->ops.tuner_ops.get_bandwidth)
 520                fe->ops.tuner_ops.get_bandwidth(fe, &p->bandwidth_hz);
 521        if (fe->ops.tuner_ops.get_frequency)
 522                fe->ops.tuner_ops.get_frequency(fe, &p->frequency);
 523        mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_HP);
 524        mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_LP);
 525        mxl1x1sf_demod_get_tps_modulation(state, &p->modulation);
 526        mxl1x1sf_demod_get_tps_guard_fft_mode(state,
 527                                              &p->transmission_mode);
 528        mxl1x1sf_demod_get_tps_guard_interval(state,
 529                                              &p->guard_interval);
 530        mxl1x1sf_demod_get_tps_hierarchy(state,
 531                                         &p->hierarchy);
 532
 533        return 0;
 534}
 535
 536static
 537int mxl111sf_demod_get_tune_settings(struct dvb_frontend *fe,
 538                                     struct dvb_frontend_tune_settings *tune)
 539{
 540        tune->min_delay_ms = 1000;
 541        return 0;
 542}
 543
 544static void mxl111sf_demod_release(struct dvb_frontend *fe)
 545{
 546        struct mxl111sf_demod_state *state = fe->demodulator_priv;
 547        mxl_dbg("()");
 548        kfree(state);
 549        fe->demodulator_priv = NULL;
 550}
 551
 552static struct dvb_frontend_ops mxl111sf_demod_ops = {
 553        .delsys = { SYS_DVBT },
 554        .info = {
 555                .name               = "MaxLinear MxL111SF DVB-T demodulator",
 556                .frequency_min      = 177000000,
 557                .frequency_max      = 858000000,
 558                .frequency_stepsize = 166666,
 559                .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 560                        FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
 561                        FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
 562                        FE_CAN_QAM_AUTO |
 563                        FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
 564                        FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
 565        },
 566        .release              = mxl111sf_demod_release,
 567#if 0
 568        .init                 = mxl111sf_init,
 569        .i2c_gate_ctrl        = mxl111sf_i2c_gate_ctrl,
 570#endif
 571        .set_frontend         = mxl111sf_demod_set_frontend,
 572        .get_frontend         = mxl111sf_demod_get_frontend,
 573        .get_tune_settings    = mxl111sf_demod_get_tune_settings,
 574        .read_status          = mxl111sf_demod_read_status,
 575        .read_signal_strength = mxl111sf_demod_read_signal_strength,
 576        .read_ber             = mxl111sf_demod_read_ber,
 577        .read_snr             = mxl111sf_demod_read_snr,
 578        .read_ucblocks        = mxl111sf_demod_read_ucblocks,
 579};
 580
 581struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
 582                                   const struct mxl111sf_demod_config *cfg)
 583{
 584        struct mxl111sf_demod_state *state = NULL;
 585
 586        mxl_dbg("()");
 587
 588        state = kzalloc(sizeof(struct mxl111sf_demod_state), GFP_KERNEL);
 589        if (state == NULL)
 590                return NULL;
 591
 592        state->mxl_state = mxl_state;
 593        state->cfg = cfg;
 594
 595        memcpy(&state->fe.ops, &mxl111sf_demod_ops,
 596               sizeof(struct dvb_frontend_ops));
 597
 598        state->fe.demodulator_priv = state;
 599        return &state->fe;
 600}
 601EXPORT_SYMBOL_GPL(mxl111sf_demod_attach);
 602
 603MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver");
 604MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
 605MODULE_LICENSE("GPL");
 606MODULE_VERSION("0.1");
 607