linux/drivers/media/dvb/frontends/dib0070.c
<<
>>
Prefs
   1/*
   2 * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
   3 *
   4 * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 *      modify it under the terms of the GNU General Public License as
   8 *      published by the Free Software Foundation, version 2.
   9 */
  10#include <linux/kernel.h>
  11#include <linux/i2c.h>
  12
  13#include "dvb_frontend.h"
  14
  15#include "dib0070.h"
  16#include "dibx000_common.h"
  17
  18static int debug;
  19module_param(debug, int, 0644);
  20MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
  21
  22#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB0070: "); printk(args); printk("\n"); } } while (0)
  23
  24#define DIB0070_P1D  0x00
  25#define DIB0070_P1F  0x01
  26#define DIB0070_P1G  0x03
  27#define DIB0070S_P1A 0x02
  28
  29struct dib0070_state {
  30        struct i2c_adapter *i2c;
  31        struct dvb_frontend *fe;
  32        const struct dib0070_config *cfg;
  33        u16 wbd_ff_offset;
  34        u8 revision;
  35};
  36
  37static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
  38{
  39        u8 b[2];
  40        struct i2c_msg msg[2] = {
  41                { .addr = state->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
  42                { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b,  .len = 2 },
  43        };
  44        if (i2c_transfer(state->i2c, msg, 2) != 2) {
  45                printk(KERN_WARNING "DiB0070 I2C read failed\n");
  46                return 0;
  47        }
  48        return (b[0] << 8) | b[1];
  49}
  50
  51static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
  52{
  53        u8 b[3] = { reg, val >> 8, val & 0xff };
  54        struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 };
  55        if (i2c_transfer(state->i2c, &msg, 1) != 1) {
  56                printk(KERN_WARNING "DiB0070 I2C write failed\n");
  57                return -EREMOTEIO;
  58        }
  59        return 0;
  60}
  61
  62#define HARD_RESET(state) do { if (state->cfg->reset) { state->cfg->reset(state->fe,1); msleep(10); state->cfg->reset(state->fe,0); msleep(10); } } while (0)
  63
  64static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
  65{
  66        struct dib0070_state *st = fe->tuner_priv;
  67        u16 tmp = 0;
  68        tmp = dib0070_read_reg(st, 0x02) & 0x3fff;
  69
  70    switch(BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)) {
  71                case  8000:
  72                        tmp |= (0 << 14);
  73                        break;
  74                case  7000:
  75                        tmp |= (1 << 14);
  76                        break;
  77        case  6000:
  78                        tmp |= (2 << 14);
  79                        break;
  80        case 5000:
  81                default:
  82                        tmp |= (3 << 14);
  83                        break;
  84        }
  85        dib0070_write_reg(st, 0x02, tmp);
  86        return 0;
  87}
  88
  89static void dib0070_captrim(struct dib0070_state *st, u16 LO4)
  90{
  91        int8_t captrim, fcaptrim, step_sign, step;
  92        u16 adc, adc_diff = 3000;
  93
  94
  95
  96        dib0070_write_reg(st, 0x0f, 0xed10);
  97        dib0070_write_reg(st, 0x17,    0x0034);
  98
  99        dib0070_write_reg(st, 0x18, 0x0032);
 100        msleep(2);
 101
 102        step = captrim = fcaptrim = 64;
 103
 104        do {
 105                step /= 2;
 106                dib0070_write_reg(st, 0x14, LO4 | captrim);
 107                msleep(1);
 108                adc = dib0070_read_reg(st, 0x19);
 109
 110                dprintk( "CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", captrim, adc, (u32) adc*(u32)1800/(u32)1024);
 111
 112                if (adc >= 400) {
 113                        adc -= 400;
 114                        step_sign = -1;
 115                } else {
 116                        adc = 400 - adc;
 117                        step_sign = 1;
 118                }
 119
 120                if (adc < adc_diff) {
 121                        dprintk( "CAPTRIM=%hd is closer to target (%hd/%hd)", captrim, adc, adc_diff);
 122                        adc_diff = adc;
 123                        fcaptrim = captrim;
 124
 125
 126
 127                }
 128                captrim += (step_sign * step);
 129        } while (step >= 1);
 130
 131        dib0070_write_reg(st, 0x14, LO4 | fcaptrim);
 132        dib0070_write_reg(st, 0x18, 0x07ff);
 133}
 134
 135#define LPF     100                       // define for the loop filter 100kHz by default 16-07-06
 136#define LO4_SET_VCO_HFDIV(l, v, h)   l |= ((v) << 11) | ((h) << 7)
 137#define LO4_SET_SD(l, s)             l |= ((s) << 14) | ((s) << 12)
 138#define LO4_SET_CTRIM(l, c)          l |=  (c) << 10
 139static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
 140{
 141        struct dib0070_state *st = fe->tuner_priv;
 142        u32 freq = ch->frequency/1000 + (BAND_OF_FREQUENCY(ch->frequency/1000) == BAND_VHF ? st->cfg->freq_offset_khz_vhf : st->cfg->freq_offset_khz_uhf);
 143
 144        u8 band = BAND_OF_FREQUENCY(freq), c;
 145
 146        /*******************VCO***********************************/
 147        u16 lo4 = 0;
 148
 149        u8 REFDIV, PRESC = 2;
 150        u32 FBDiv, Rest, FREF, VCOF_kHz;
 151        u16 Num, Den;
 152        /*******************FrontEnd******************************/
 153        u16 value = 0;
 154
 155        dprintk( "Tuning for Band: %hd (%d kHz)", band, freq);
 156
 157
 158        dib0070_write_reg(st, 0x17, 0x30);
 159
 160        dib0070_set_bandwidth(fe, ch);  /* c is used as HF */
 161        switch (st->revision) {
 162                case DIB0070S_P1A:
 163                        switch (band) {
 164                                case BAND_LBAND:
 165                                        LO4_SET_VCO_HFDIV(lo4, 1, 1);
 166                                        c = 2;
 167                                        break;
 168                                case BAND_SBAND:
 169                                        LO4_SET_VCO_HFDIV(lo4, 0, 0);
 170                                        LO4_SET_CTRIM(lo4, 1);;
 171                                        c = 1;
 172                                        break;
 173                                case BAND_UHF:
 174                                default:
 175                                        if (freq < 570000) {
 176                                                LO4_SET_VCO_HFDIV(lo4, 1, 3);
 177                                                PRESC = 6; c = 6;
 178                                        } else if (freq < 680000) {
 179                                                LO4_SET_VCO_HFDIV(lo4, 0, 2);
 180                                                c = 4;
 181                                        } else {
 182                                                LO4_SET_VCO_HFDIV(lo4, 1, 2);
 183                                                c = 4;
 184                                        }
 185                                        break;
 186                        } break;
 187
 188                case DIB0070_P1G:
 189                case DIB0070_P1F:
 190                default:
 191                        switch (band) {
 192                                case BAND_FM:
 193                                                LO4_SET_VCO_HFDIV(lo4, 0, 7);
 194                                                c = 24;
 195                                        break;
 196                                case BAND_LBAND:
 197                                                LO4_SET_VCO_HFDIV(lo4, 1, 0);
 198                                                c = 2;
 199                                        break;
 200                                case BAND_VHF:
 201                                        if (freq < 180000) {
 202                                                LO4_SET_VCO_HFDIV(lo4, 0, 3);
 203                                                c = 16;
 204                                        } else if (freq < 190000) {
 205                                                LO4_SET_VCO_HFDIV(lo4, 1, 3);
 206                                                c = 16;
 207                                        } else {
 208                                                LO4_SET_VCO_HFDIV(lo4, 0, 6);
 209                                                c = 12;
 210                                        }
 211                                        break;
 212
 213                                case BAND_UHF:
 214                                default:
 215                                        if (freq < 570000) {
 216                                                LO4_SET_VCO_HFDIV(lo4, 1, 5);
 217                                                c = 6;
 218                                        } else if (freq < 700000) {
 219                                                LO4_SET_VCO_HFDIV(lo4, 0, 1);
 220                                                c = 4;
 221                                        } else {
 222                                                LO4_SET_VCO_HFDIV(lo4, 1, 1);
 223                                                c = 4;
 224                                        }
 225                                        break;
 226                        }
 227                break;
 228        }
 229
 230        dprintk( "HFDIV code: %hd", (lo4 >> 7) & 0xf);
 231        dprintk( "VCO = %hd", (lo4 >> 11) & 0x3);
 232
 233
 234        VCOF_kHz = (c * freq) * 2;
 235        dprintk( "VCOF in kHz: %d ((%hd*%d) << 1))",VCOF_kHz, c, freq);
 236
 237        switch (band) {
 238                case BAND_VHF:
 239                        REFDIV = (u8) ((st->cfg->clock_khz + 9999) / 10000);
 240                        break;
 241                case BAND_FM:
 242                        REFDIV = (u8) ((st->cfg->clock_khz) / 1000);
 243                        break;
 244                default:
 245                        REFDIV = (u8) ( st->cfg->clock_khz  / 10000);
 246                        break;
 247        }
 248        FREF = st->cfg->clock_khz / REFDIV;
 249
 250        dprintk( "REFDIV: %hd, FREF: %d", REFDIV, FREF);
 251
 252
 253
 254        switch (st->revision) {
 255                case DIB0070S_P1A:
 256                        FBDiv = (VCOF_kHz / PRESC / FREF);
 257                        Rest  = (VCOF_kHz / PRESC) - FBDiv * FREF;
 258                        break;
 259
 260                case DIB0070_P1G:
 261                case DIB0070_P1F:
 262                default:
 263                        FBDiv = (freq / (FREF / 2));
 264                        Rest  = 2 * freq - FBDiv * FREF;
 265                        break;
 266        }
 267
 268
 269             if (Rest < LPF)              Rest = 0;
 270        else if (Rest < 2 * LPF)          Rest = 2 * LPF;
 271        else if (Rest > (FREF - LPF))   { Rest = 0 ; FBDiv += 1; }
 272        else if (Rest > (FREF - 2 * LPF)) Rest = FREF - 2 * LPF;
 273        Rest = (Rest * 6528) / (FREF / 10);
 274        dprintk( "FBDIV: %d, Rest: %d", FBDiv, Rest);
 275
 276        Num = 0;
 277        Den = 1;
 278
 279        if (Rest > 0) {
 280                LO4_SET_SD(lo4, 1);
 281                Den = 255;
 282                Num = (u16)Rest;
 283        }
 284        dprintk( "Num: %hd, Den: %hd, SD: %hd",Num, Den, (lo4 >> 12) & 0x1);
 285
 286
 287
 288        dib0070_write_reg(st, 0x11, (u16)FBDiv);
 289
 290
 291        dib0070_write_reg(st, 0x12, (Den << 8) | REFDIV);
 292
 293
 294        dib0070_write_reg(st, 0x13, Num);
 295
 296
 297        value = 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001;
 298
 299        switch (band) {
 300                case BAND_UHF:   value |= 0x4000 | 0x0800; break;
 301                case BAND_LBAND: value |= 0x2000 | 0x0400; break;
 302                default:         value |= 0x8000 | 0x1000; break;
 303        }
 304        dib0070_write_reg(st, 0x20, value);
 305
 306        dib0070_captrim(st, lo4);
 307        if (st->revision == DIB0070S_P1A) {
 308                if (band == BAND_SBAND)
 309                        dib0070_write_reg(st, 0x15, 0x16e2);
 310                else
 311                        dib0070_write_reg(st, 0x15, 0x56e5);
 312        }
 313
 314
 315
 316        switch (band) {
 317                case BAND_UHF:   value = 0x7c82; break;
 318                case BAND_LBAND: value = 0x7c84; break;
 319                default:         value = 0x7c81; break;
 320        }
 321        dib0070_write_reg(st, 0x0f, value);
 322        dib0070_write_reg(st, 0x06, 0x3fff);
 323
 324        /* Front End */
 325        /* c == TUNE, value = SWITCH */
 326        c = 0;
 327        value = 0;
 328        switch (band) {
 329                case BAND_FM:
 330                        c = 0; value = 1;
 331                break;
 332
 333                case BAND_VHF:
 334                        if (freq <= 180000) c = 0;
 335                        else if (freq <= 188200) c = 1;
 336                        else if (freq <= 196400) c = 2;
 337                        else c = 3;
 338                        value = 1;
 339                break;
 340
 341                case BAND_LBAND:
 342                        if (freq <= 1500000) c = 0;
 343                        else if (freq <= 1600000) c = 1;
 344                        else c = 3;
 345                break;
 346
 347                case BAND_SBAND:
 348                        c = 7;
 349                        dib0070_write_reg(st, 0x1d,0xFFFF);
 350                break;
 351
 352                case BAND_UHF:
 353                default:
 354                        if (st->cfg->flip_chip) {
 355                                if (freq <= 550000) c = 0;
 356                                else if (freq <= 590000) c = 1;
 357                                else if (freq <= 666000) c = 3;
 358                                else c = 5;
 359                        } else {
 360                                if (freq <= 550000) c = 2;
 361                                else if (freq <= 650000) c = 3;
 362                                else if (freq <= 750000) c = 5;
 363                                else if (freq <= 850000) c = 6;
 364                                else c = 7;
 365                        }
 366                        value = 2;
 367                break;
 368        }
 369
 370        /* default: LNA_MATCH=7, BIAS=3 */
 371        dib0070_write_reg(st, 0x07, (value << 11) | (7 << 8) | (c << 3) | (3 << 0));
 372        dib0070_write_reg(st, 0x08, (c << 10) | (3 << 7) | (127));
 373        dib0070_write_reg(st, 0x0d, 0x0d80);
 374
 375
 376        dib0070_write_reg(st, 0x18,   0x07ff);
 377        dib0070_write_reg(st, 0x17, 0x0033);
 378
 379        return 0;
 380}
 381
 382static int dib0070_wakeup(struct dvb_frontend *fe)
 383{
 384        struct dib0070_state *st = fe->tuner_priv;
 385        if (st->cfg->sleep)
 386                st->cfg->sleep(fe, 0);
 387        return 0;
 388}
 389
 390static int dib0070_sleep(struct dvb_frontend *fe)
 391{
 392        struct dib0070_state *st = fe->tuner_priv;
 393        if (st->cfg->sleep)
 394                st->cfg->sleep(fe, 1);
 395        return 0;
 396}
 397
 398static u16 dib0070_p1f_defaults[] =
 399
 400{
 401        7, 0x02,
 402                0x0008,
 403                0x0000,
 404                0x0000,
 405                0x0000,
 406                0x0000,
 407                0x0002,
 408                0x0100,
 409
 410        3, 0x0d,
 411                0x0d80,
 412                0x0001,
 413                0x0000,
 414
 415        4, 0x11,
 416                0x0000,
 417                0x0103,
 418                0x0000,
 419                0x0000,
 420
 421        3, 0x16,
 422                0x0004 | 0x0040,
 423                0x0030,
 424                0x07ff,
 425
 426        6, 0x1b,
 427                0x4112,
 428                0xff00,
 429                0xc07f,
 430                0x0000,
 431                0x0180,
 432                0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
 433
 434        0,
 435};
 436
 437static void dib0070_wbd_calibration(struct dib0070_state *state)
 438{
 439        u16 wbd_offs;
 440        dib0070_write_reg(state, 0x0f, 0x6d81);
 441        dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
 442        msleep(9);
 443        wbd_offs = dib0070_read_reg(state, 0x19);
 444        dib0070_write_reg(state, 0x20, 0);
 445        state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2);
 446        dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset);
 447}
 448
 449u16 dib0070_wbd_offset(struct dvb_frontend *fe)
 450{
 451        struct dib0070_state *st = fe->tuner_priv;
 452        return st->wbd_ff_offset;
 453}
 454
 455EXPORT_SYMBOL(dib0070_wbd_offset);
 456static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
 457{
 458        struct dib0070_state *state = fe->tuner_priv;
 459    u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
 460        dprintk( "CTRL_LO5: 0x%x", lo5);
 461        return dib0070_write_reg(state, 0x15, lo5);
 462}
 463
 464#define pgm_read_word(w) (*w)
 465static int dib0070_reset(struct dib0070_state *state)
 466{
 467        u16 l, r, *n;
 468
 469        HARD_RESET(state);
 470
 471
 472#ifndef FORCE_SBAND_TUNER
 473        if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
 474                state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
 475        else
 476#endif
 477                state->revision = DIB0070S_P1A;
 478
 479        /* P1F or not */
 480        dprintk( "Revision: %x", state->revision);
 481
 482        if (state->revision == DIB0070_P1D) {
 483                dprintk( "Error: this driver is not to be used meant for P1D or earlier");
 484                return -EINVAL;
 485        }
 486
 487        n = (u16 *) dib0070_p1f_defaults;
 488        l = pgm_read_word(n++);
 489        while (l) {
 490                r = pgm_read_word(n++);
 491                do {
 492                        dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
 493                        r++;
 494                } while (--l);
 495                l = pgm_read_word(n++);
 496        }
 497
 498        if (state->cfg->force_crystal_mode != 0)
 499                r = state->cfg->force_crystal_mode;
 500        else if (state->cfg->clock_khz >= 24000)
 501                r = 1;
 502        else
 503                r = 2;
 504
 505        r |= state->cfg->osc_buffer_state << 3;
 506
 507        dib0070_write_reg(state, 0x10, r);
 508        dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 4));
 509
 510        if (state->cfg->invert_iq) {
 511                r = dib0070_read_reg(state, 0x02) & 0xffdf;
 512                dib0070_write_reg(state, 0x02, r | (1 << 5));
 513        }
 514
 515
 516        if (state->revision == DIB0070S_P1A)
 517                dib0070_set_ctrl_lo5(state->fe, 4, 7, 3, 1);
 518        else
 519                dib0070_set_ctrl_lo5(state->fe, 4, 4, 2, 0);
 520
 521        dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
 522        return 0;
 523}
 524
 525
 526static int dib0070_release(struct dvb_frontend *fe)
 527{
 528        kfree(fe->tuner_priv);
 529        fe->tuner_priv = NULL;
 530        return 0;
 531}
 532
 533static struct dvb_tuner_ops dib0070_ops = {
 534        .info = {
 535                .name           = "DiBcom DiB0070",
 536                .frequency_min  =  45000000,
 537                .frequency_max  = 860000000,
 538                .frequency_step =      1000,
 539        },
 540        .release       = dib0070_release,
 541
 542        .init          = dib0070_wakeup,
 543        .sleep         = dib0070_sleep,
 544        .set_params    = dib0070_tune_digital,
 545//      .get_frequency = dib0070_get_frequency,
 546//      .get_bandwidth = dib0070_get_bandwidth
 547};
 548
 549struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
 550{
 551        struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
 552        if (state == NULL)
 553                return NULL;
 554
 555        state->cfg = cfg;
 556        state->i2c = i2c;
 557        state->fe  = fe;
 558        fe->tuner_priv = state;
 559
 560        if (dib0070_reset(state) != 0)
 561                goto free_mem;
 562
 563        dib0070_wbd_calibration(state);
 564
 565        printk(KERN_INFO "DiB0070: successfully identified\n");
 566        memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
 567
 568        fe->tuner_priv = state;
 569        return fe;
 570
 571free_mem:
 572        kfree(state);
 573        fe->tuner_priv = NULL;
 574        return NULL;
 575}
 576EXPORT_SYMBOL(dib0070_attach);
 577
 578MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
 579MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
 580MODULE_LICENSE("GPL");
 581