linux/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
<<
>>
Prefs
   1/*
   2 *  mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner
   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
  17#include "mxl111sf-tuner.h"
  18#include "mxl111sf-phy.h"
  19#include "mxl111sf-reg.h"
  20
  21/* debug */
  22static int mxl111sf_tuner_debug;
  23module_param_named(debug, mxl111sf_tuner_debug, int, 0644);
  24MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
  25
  26#define mxl_dbg(fmt, arg...) \
  27        if (mxl111sf_tuner_debug) \
  28                mxl_printk(KERN_DEBUG, fmt, ##arg)
  29
  30/* ------------------------------------------------------------------------ */
  31
  32struct mxl111sf_tuner_state {
  33        struct mxl111sf_state *mxl_state;
  34
  35        const struct mxl111sf_tuner_config *cfg;
  36
  37        enum mxl_if_freq if_freq;
  38
  39        u32 frequency;
  40        u32 bandwidth;
  41};
  42
  43static int mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state *state,
  44                                   u8 addr, u8 *data)
  45{
  46        return (state->cfg->read_reg) ?
  47                state->cfg->read_reg(state->mxl_state, addr, data) :
  48                -EINVAL;
  49}
  50
  51static int mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state *state,
  52                                    u8 addr, u8 data)
  53{
  54        return (state->cfg->write_reg) ?
  55                state->cfg->write_reg(state->mxl_state, addr, data) :
  56                -EINVAL;
  57}
  58
  59static int mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state *state,
  60                               struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
  61{
  62        return (state->cfg->program_regs) ?
  63                state->cfg->program_regs(state->mxl_state, ctrl_reg_info) :
  64                -EINVAL;
  65}
  66
  67static int mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state *state,
  68                                          int onoff)
  69{
  70        return (state->cfg->top_master_ctrl) ?
  71                state->cfg->top_master_ctrl(state->mxl_state, onoff) :
  72                -EINVAL;
  73}
  74
  75/* ------------------------------------------------------------------------ */
  76
  77static struct mxl111sf_reg_ctrl_info mxl_phy_tune_rf[] = {
  78        {0x1d, 0x7f, 0x00}, /* channel bandwidth section 1/2/3,
  79                               DIG_MODEINDEX, _A, _CSF, */
  80        {0x1e, 0xff, 0x00}, /* channel frequency (lo and fractional) */
  81        {0x1f, 0xff, 0x00}, /* channel frequency (hi for integer portion) */
  82        {0,    0,    0}
  83};
  84
  85/* ------------------------------------------------------------------------ */
  86
  87static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq,
  88                                                                  u8 bw)
  89{
  90        u8 filt_bw;
  91
  92        /* set channel bandwidth */
  93        switch (bw) {
  94        case 0: /* ATSC */
  95                filt_bw = 25;
  96                break;
  97        case 1: /* QAM */
  98                filt_bw = 69;
  99                break;
 100        case 6:
 101                filt_bw = 21;
 102                break;
 103        case 7:
 104                filt_bw = 42;
 105                break;
 106        case 8:
 107                filt_bw = 63;
 108                break;
 109        default:
 110                pr_err("%s: invalid bandwidth setting!", __func__);
 111                return NULL;
 112        }
 113
 114        /* calculate RF channel */
 115        freq /= 1000000;
 116
 117        freq *= 64;
 118#if 0
 119        /* do round */
 120        freq += 0.5;
 121#endif
 122        /* set bandwidth */
 123        mxl_phy_tune_rf[0].data = filt_bw;
 124
 125        /* set RF */
 126        mxl_phy_tune_rf[1].data = (freq & 0xff);
 127        mxl_phy_tune_rf[2].data = (freq >> 8) & 0xff;
 128
 129        /* start tune */
 130        return mxl_phy_tune_rf;
 131}
 132
 133static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state)
 134{
 135        int ret;
 136        u8 ctrl;
 137#if 0
 138        u16 iffcw;
 139        u32 if_freq;
 140#endif
 141        mxl_dbg("(IF polarity = %d, IF freq = 0x%02x)",
 142                state->cfg->invert_spectrum, state->cfg->if_freq);
 143
 144        /* set IF polarity */
 145        ctrl = state->cfg->invert_spectrum;
 146
 147        ctrl |= state->cfg->if_freq;
 148
 149        ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_SEL_REG, ctrl);
 150        if (mxl_fail(ret))
 151                goto fail;
 152
 153#if 0
 154        if_freq /= 1000000;
 155
 156        /* do round */
 157        if_freq += 0.5;
 158
 159        if (MXL_IF_LO == state->cfg->if_freq) {
 160                ctrl = 0x08;
 161                iffcw = (u16)(if_freq / (108 * 4096));
 162        } else if (MXL_IF_HI == state->cfg->if_freq) {
 163                ctrl = 0x08;
 164                iffcw = (u16)(if_freq / (216 * 4096));
 165        } else {
 166                ctrl = 0;
 167                iffcw = 0;
 168        }
 169
 170        ctrl |= (iffcw >> 8);
 171#endif
 172        ret = mxl111sf_tuner_read_reg(state, V6_TUNER_IF_FCW_BYP_REG, &ctrl);
 173        if (mxl_fail(ret))
 174                goto fail;
 175
 176        ctrl &= 0xf0;
 177        ctrl |= 0x90;
 178
 179        ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_BYP_REG, ctrl);
 180        if (mxl_fail(ret))
 181                goto fail;
 182
 183#if 0
 184        ctrl = iffcw & 0x00ff;
 185#endif
 186        ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl);
 187        if (mxl_fail(ret))
 188                goto fail;
 189
 190        state->if_freq = state->cfg->if_freq;
 191fail:
 192        return ret;
 193}
 194
 195static int mxl1x1sf_tune_rf(struct dvb_frontend *fe, u32 freq, u8 bw)
 196{
 197        struct mxl111sf_tuner_state *state = fe->tuner_priv;
 198        static struct mxl111sf_reg_ctrl_info *reg_ctrl_array;
 199        int ret;
 200        u8 mxl_mode;
 201
 202        mxl_dbg("(freq = %d, bw = 0x%x)", freq, bw);
 203
 204        /* stop tune */
 205        ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 0);
 206        if (mxl_fail(ret))
 207                goto fail;
 208
 209        /* check device mode */
 210        ret = mxl111sf_tuner_read_reg(state, MXL_MODE_REG, &mxl_mode);
 211        if (mxl_fail(ret))
 212                goto fail;
 213
 214        /* Fill out registers for channel tune */
 215        reg_ctrl_array = mxl111sf_calc_phy_tune_regs(freq, bw);
 216        if (!reg_ctrl_array)
 217                return -EINVAL;
 218
 219        ret = mxl111sf_tuner_program_regs(state, reg_ctrl_array);
 220        if (mxl_fail(ret))
 221                goto fail;
 222
 223        if ((mxl_mode & MXL_DEV_MODE_MASK) == MXL_TUNER_MODE) {
 224                /* IF tuner mode only */
 225                mxl1x1sf_tuner_top_master_ctrl(state, 0);
 226                mxl1x1sf_tuner_top_master_ctrl(state, 1);
 227                mxl1x1sf_tuner_set_if_output_freq(state);
 228        }
 229
 230        ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 1);
 231        if (mxl_fail(ret))
 232                goto fail;
 233
 234        if (state->cfg->ant_hunt)
 235                state->cfg->ant_hunt(fe);
 236fail:
 237        return ret;
 238}
 239
 240static int mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state *state,
 241                                          int *rf_synth_lock,
 242                                          int *ref_synth_lock)
 243{
 244        int ret;
 245        u8 data;
 246
 247        *rf_synth_lock = 0;
 248        *ref_synth_lock = 0;
 249
 250        ret = mxl111sf_tuner_read_reg(state, V6_RF_LOCK_STATUS_REG, &data);
 251        if (mxl_fail(ret))
 252                goto fail;
 253
 254        *ref_synth_lock = ((data & 0x03) == 0x03) ? 1 : 0;
 255        *rf_synth_lock  = ((data & 0x0c) == 0x0c) ? 1 : 0;
 256fail:
 257        return ret;
 258}
 259
 260#if 0
 261static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state,
 262                                         int onoff)
 263{
 264        return mxl111sf_tuner_write_reg(state, V6_TUNER_LOOP_THRU_CTRL_REG,
 265                                        onoff ? 1 : 0);
 266}
 267#endif
 268
 269/* ------------------------------------------------------------------------ */
 270
 271static int mxl111sf_tuner_set_params(struct dvb_frontend *fe)
 272{
 273        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 274        u32 delsys  = c->delivery_system;
 275        struct mxl111sf_tuner_state *state = fe->tuner_priv;
 276        int ret;
 277        u8 bw;
 278
 279        mxl_dbg("()");
 280
 281        switch (delsys) {
 282        case SYS_ATSC:
 283        case SYS_ATSCMH:
 284                bw = 0; /* ATSC */
 285                break;
 286        case SYS_DVBC_ANNEX_B:
 287                bw = 1; /* US CABLE */
 288                break;
 289        case SYS_DVBT:
 290                switch (c->bandwidth_hz) {
 291                case 6000000:
 292                        bw = 6;
 293                        break;
 294                case 7000000:
 295                        bw = 7;
 296                        break;
 297                case 8000000:
 298                        bw = 8;
 299                        break;
 300                default:
 301                        pr_err("%s: bandwidth not set!", __func__);
 302                        return -EINVAL;
 303                }
 304                break;
 305        default:
 306                pr_err("%s: modulation type not supported!", __func__);
 307                return -EINVAL;
 308        }
 309        ret = mxl1x1sf_tune_rf(fe, c->frequency, bw);
 310        if (mxl_fail(ret))
 311                goto fail;
 312
 313        state->frequency = c->frequency;
 314        state->bandwidth = c->bandwidth_hz;
 315fail:
 316        return ret;
 317}
 318
 319/* ------------------------------------------------------------------------ */
 320
 321#if 0
 322static int mxl111sf_tuner_init(struct dvb_frontend *fe)
 323{
 324        struct mxl111sf_tuner_state *state = fe->tuner_priv;
 325        int ret;
 326
 327        /* wake from standby handled by usb driver */
 328
 329        return ret;
 330}
 331
 332static int mxl111sf_tuner_sleep(struct dvb_frontend *fe)
 333{
 334        struct mxl111sf_tuner_state *state = fe->tuner_priv;
 335        int ret;
 336
 337        /* enter standby mode handled by usb driver */
 338
 339        return ret;
 340}
 341#endif
 342
 343/* ------------------------------------------------------------------------ */
 344
 345static int mxl111sf_tuner_get_status(struct dvb_frontend *fe, u32 *status)
 346{
 347        struct mxl111sf_tuner_state *state = fe->tuner_priv;
 348        int rf_locked, ref_locked, ret;
 349
 350        *status = 0;
 351
 352        ret = mxl1x1sf_tuner_get_lock_status(state, &rf_locked, &ref_locked);
 353        if (mxl_fail(ret))
 354                goto fail;
 355        mxl_info("%s%s", rf_locked ? "rf locked " : "",
 356                 ref_locked ? "ref locked" : "");
 357
 358        if ((rf_locked) || (ref_locked))
 359                *status |= TUNER_STATUS_LOCKED;
 360fail:
 361        return ret;
 362}
 363
 364static int mxl111sf_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
 365{
 366        struct mxl111sf_tuner_state *state = fe->tuner_priv;
 367        u8 val1, val2;
 368        int ret;
 369
 370        *strength = 0;
 371
 372        ret = mxl111sf_tuner_write_reg(state, 0x00, 0x02);
 373        if (mxl_fail(ret))
 374                goto fail;
 375        ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_LSB_REG, &val1);
 376        if (mxl_fail(ret))
 377                goto fail;
 378        ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_MSB_REG, &val2);
 379        if (mxl_fail(ret))
 380                goto fail;
 381
 382        *strength = val1 | ((val2 & 0x07) << 8);
 383fail:
 384        ret = mxl111sf_tuner_write_reg(state, 0x00, 0x00);
 385        mxl_fail(ret);
 386
 387        return ret;
 388}
 389
 390/* ------------------------------------------------------------------------ */
 391
 392static int mxl111sf_tuner_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 393{
 394        struct mxl111sf_tuner_state *state = fe->tuner_priv;
 395        *frequency = state->frequency;
 396        return 0;
 397}
 398
 399static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
 400{
 401        struct mxl111sf_tuner_state *state = fe->tuner_priv;
 402        *bandwidth = state->bandwidth;
 403        return 0;
 404}
 405
 406static int mxl111sf_tuner_get_if_frequency(struct dvb_frontend *fe,
 407                                           u32 *frequency)
 408{
 409        struct mxl111sf_tuner_state *state = fe->tuner_priv;
 410
 411        *frequency = 0;
 412
 413        switch (state->if_freq) {
 414        case MXL_IF_4_0:   /* 4.0   MHz */
 415                *frequency = 4000000;
 416                break;
 417        case MXL_IF_4_5:   /* 4.5   MHz */
 418                *frequency = 4500000;
 419                break;
 420        case MXL_IF_4_57:  /* 4.57  MHz */
 421                *frequency = 4570000;
 422                break;
 423        case MXL_IF_5_0:   /* 5.0   MHz */
 424                *frequency = 5000000;
 425                break;
 426        case MXL_IF_5_38:  /* 5.38  MHz */
 427                *frequency = 5380000;
 428                break;
 429        case MXL_IF_6_0:   /* 6.0   MHz */
 430                *frequency = 6000000;
 431                break;
 432        case MXL_IF_6_28:  /* 6.28  MHz */
 433                *frequency = 6280000;
 434                break;
 435        case MXL_IF_7_2:   /* 7.2   MHz */
 436                *frequency = 7200000;
 437                break;
 438        case MXL_IF_35_25: /* 35.25 MHz */
 439                *frequency = 35250000;
 440                break;
 441        case MXL_IF_36:    /* 36    MHz */
 442                *frequency = 36000000;
 443                break;
 444        case MXL_IF_36_15: /* 36.15 MHz */
 445                *frequency = 36150000;
 446                break;
 447        case MXL_IF_44:    /* 44    MHz */
 448                *frequency = 44000000;
 449                break;
 450        }
 451        return 0;
 452}
 453
 454static void mxl111sf_tuner_release(struct dvb_frontend *fe)
 455{
 456        struct mxl111sf_tuner_state *state = fe->tuner_priv;
 457        mxl_dbg("()");
 458        kfree(state);
 459        fe->tuner_priv = NULL;
 460}
 461
 462/* ------------------------------------------------------------------------- */
 463
 464static const struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = {
 465        .info = {
 466                .name = "MaxLinear MxL111SF",
 467#if 0
 468                .frequency_min  = ,
 469                .frequency_max  = ,
 470                .frequency_step = ,
 471#endif
 472        },
 473#if 0
 474        .init              = mxl111sf_tuner_init,
 475        .sleep             = mxl111sf_tuner_sleep,
 476#endif
 477        .set_params        = mxl111sf_tuner_set_params,
 478        .get_status        = mxl111sf_tuner_get_status,
 479        .get_rf_strength   = mxl111sf_get_rf_strength,
 480        .get_frequency     = mxl111sf_tuner_get_frequency,
 481        .get_bandwidth     = mxl111sf_tuner_get_bandwidth,
 482        .get_if_frequency  = mxl111sf_tuner_get_if_frequency,
 483        .release           = mxl111sf_tuner_release,
 484};
 485
 486struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
 487                                struct mxl111sf_state *mxl_state,
 488                                const struct mxl111sf_tuner_config *cfg)
 489{
 490        struct mxl111sf_tuner_state *state = NULL;
 491
 492        mxl_dbg("()");
 493
 494        state = kzalloc(sizeof(struct mxl111sf_tuner_state), GFP_KERNEL);
 495        if (state == NULL)
 496                return NULL;
 497
 498        state->mxl_state = mxl_state;
 499        state->cfg = cfg;
 500
 501        memcpy(&fe->ops.tuner_ops, &mxl111sf_tuner_tuner_ops,
 502               sizeof(struct dvb_tuner_ops));
 503
 504        fe->tuner_priv = state;
 505        return fe;
 506}
 507EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach);
 508
 509MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver");
 510MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
 511MODULE_LICENSE("GPL");
 512MODULE_VERSION("0.1");
 513