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-9 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; either version 2 of the
   9 * License, or (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful, but
  12 * WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 *
  21 *
  22 * This code is more or less generated from another driver, please
  23 * excuse some codingstyle oddities.
  24 *
  25 */
  26
  27#include <linux/kernel.h>
  28#include <linux/slab.h>
  29#include <linux/i2c.h>
  30#include <linux/mutex.h>
  31
  32#include "dvb_frontend.h"
  33
  34#include "dib0070.h"
  35#include "dibx000_common.h"
  36
  37static int debug;
  38module_param(debug, int, 0644);
  39MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
  40
  41#define dprintk(args...) do { \
  42        if (debug) { \
  43                printk(KERN_DEBUG "DiB0070: "); \
  44                printk(args); \
  45                printk("\n"); \
  46        } \
  47} while (0)
  48
  49#define DIB0070_P1D  0x00
  50#define DIB0070_P1F  0x01
  51#define DIB0070_P1G  0x03
  52#define DIB0070S_P1A 0x02
  53
  54struct dib0070_state {
  55        struct i2c_adapter *i2c;
  56        struct dvb_frontend *fe;
  57        const struct dib0070_config *cfg;
  58        u16 wbd_ff_offset;
  59        u8 revision;
  60
  61    enum frontend_tune_state tune_state;
  62    u32 current_rf;
  63
  64    /* for the captrim binary search */
  65        s8 step;
  66        u16 adc_diff;
  67
  68        s8 captrim;
  69        s8 fcaptrim;
  70        u16 lo4;
  71
  72        const struct dib0070_tuning *current_tune_table_index;
  73        const struct dib0070_lna_match *lna_match;
  74
  75    u8  wbd_gain_current;
  76        u16 wbd_offset_3_3[2];
  77
  78        /* for the I2C transfer */
  79        struct i2c_msg msg[2];
  80        u8 i2c_write_buffer[3];
  81        u8 i2c_read_buffer[2];
  82        struct mutex i2c_buffer_lock;
  83};
  84
  85static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg)
  86{
  87        u16 ret;
  88
  89        if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
  90                dprintk("could not acquire lock");
  91                return 0;
  92        }
  93
  94        state->i2c_write_buffer[0] = reg;
  95
  96        memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
  97        state->msg[0].addr = state->cfg->i2c_address;
  98        state->msg[0].flags = 0;
  99        state->msg[0].buf = state->i2c_write_buffer;
 100        state->msg[0].len = 1;
 101        state->msg[1].addr = state->cfg->i2c_address;
 102        state->msg[1].flags = I2C_M_RD;
 103        state->msg[1].buf = state->i2c_read_buffer;
 104        state->msg[1].len = 2;
 105
 106        if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
 107                printk(KERN_WARNING "DiB0070 I2C read failed\n");
 108                ret = 0;
 109        } else
 110                ret = (state->i2c_read_buffer[0] << 8)
 111                        | state->i2c_read_buffer[1];
 112
 113        mutex_unlock(&state->i2c_buffer_lock);
 114        return ret;
 115}
 116
 117static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
 118{
 119        int ret;
 120
 121        if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
 122                dprintk("could not acquire lock");
 123                return -EINVAL;
 124        }
 125        state->i2c_write_buffer[0] = reg;
 126        state->i2c_write_buffer[1] = val >> 8;
 127        state->i2c_write_buffer[2] = val & 0xff;
 128
 129        memset(state->msg, 0, sizeof(struct i2c_msg));
 130        state->msg[0].addr = state->cfg->i2c_address;
 131        state->msg[0].flags = 0;
 132        state->msg[0].buf = state->i2c_write_buffer;
 133        state->msg[0].len = 3;
 134
 135        if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
 136                printk(KERN_WARNING "DiB0070 I2C write failed\n");
 137                ret = -EREMOTEIO;
 138        } else
 139                ret = 0;
 140
 141        mutex_unlock(&state->i2c_buffer_lock);
 142        return ret;
 143}
 144
 145#define HARD_RESET(state) do { \
 146    state->cfg->sleep(state->fe, 0); \
 147    if (state->cfg->reset) { \
 148        state->cfg->reset(state->fe,1); msleep(10); \
 149        state->cfg->reset(state->fe,0); msleep(10); \
 150    } \
 151} while (0)
 152
 153static int dib0070_set_bandwidth(struct dvb_frontend *fe)
 154{
 155    struct dib0070_state *state = fe->tuner_priv;
 156    u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff;
 157
 158    if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000)
 159        tmp |= (0 << 14);
 160    else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000)
 161        tmp |= (1 << 14);
 162    else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000)
 163        tmp |= (2 << 14);
 164    else
 165        tmp |= (3 << 14);
 166
 167    dib0070_write_reg(state, 0x02, tmp);
 168
 169    /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */
 170    if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) {
 171        u16 value = dib0070_read_reg(state, 0x17);
 172
 173        dib0070_write_reg(state, 0x17, value & 0xfffc);
 174        tmp = dib0070_read_reg(state, 0x01) & 0x01ff;
 175        dib0070_write_reg(state, 0x01, tmp | (60 << 9));
 176
 177        dib0070_write_reg(state, 0x17, value);
 178    }
 179        return 0;
 180}
 181
 182static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state *tune_state)
 183{
 184        int8_t step_sign;
 185        u16 adc;
 186        int ret = 0;
 187
 188        if (*tune_state == CT_TUNER_STEP_0) {
 189
 190                dib0070_write_reg(state, 0x0f, 0xed10);
 191                dib0070_write_reg(state, 0x17,    0x0034);
 192
 193                dib0070_write_reg(state, 0x18, 0x0032);
 194                state->step = state->captrim = state->fcaptrim = 64;
 195                state->adc_diff = 3000;
 196                ret = 20;
 197
 198        *tune_state = CT_TUNER_STEP_1;
 199        } else if (*tune_state == CT_TUNER_STEP_1) {
 200                state->step /= 2;
 201                dib0070_write_reg(state, 0x14, state->lo4 | state->captrim);
 202                ret = 15;
 203
 204                *tune_state = CT_TUNER_STEP_2;
 205        } else if (*tune_state == CT_TUNER_STEP_2) {
 206
 207                adc = dib0070_read_reg(state, 0x19);
 208
 209                dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024);
 210
 211                if (adc >= 400) {
 212                        adc -= 400;
 213                        step_sign = -1;
 214                } else {
 215                        adc = 400 - adc;
 216                        step_sign = 1;
 217                }
 218
 219                if (adc < state->adc_diff) {
 220                        dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)", state->captrim, adc, state->adc_diff);
 221                        state->adc_diff = adc;
 222                        state->fcaptrim = state->captrim;
 223
 224
 225
 226                }
 227                state->captrim += (step_sign * state->step);
 228
 229                if (state->step >= 1)
 230                        *tune_state = CT_TUNER_STEP_1;
 231                else
 232                        *tune_state = CT_TUNER_STEP_3;
 233
 234        } else if (*tune_state == CT_TUNER_STEP_3) {
 235                dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim);
 236                dib0070_write_reg(state, 0x18, 0x07ff);
 237                *tune_state = CT_TUNER_STEP_4;
 238        }
 239
 240        return ret;
 241}
 242
 243static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
 244{
 245        struct dib0070_state *state = fe->tuner_priv;
 246    u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
 247        dprintk("CTRL_LO5: 0x%x", lo5);
 248        return dib0070_write_reg(state, 0x15, lo5);
 249}
 250
 251void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)
 252{
 253        struct dib0070_state *state = fe->tuner_priv;
 254
 255        if (open) {
 256                dib0070_write_reg(state, 0x1b, 0xff00);
 257                dib0070_write_reg(state, 0x1a, 0x0000);
 258        } else {
 259                dib0070_write_reg(state, 0x1b, 0x4112);
 260        if (state->cfg->vga_filter != 0) {
 261                dib0070_write_reg(state, 0x1a, state->cfg->vga_filter);
 262                dprintk("vga filter register is set to %x", state->cfg->vga_filter);
 263        } else
 264                dib0070_write_reg(state, 0x1a, 0x0009);
 265        }
 266}
 267
 268EXPORT_SYMBOL(dib0070_ctrl_agc_filter);
 269struct dib0070_tuning {
 270    u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
 271    u8 switch_trim;
 272    u8 vco_band;
 273    u8 hfdiv;
 274    u8 vco_multi;
 275    u8 presc;
 276    u8 wbdmux;
 277    u16 tuner_enable;
 278};
 279
 280struct dib0070_lna_match {
 281    u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
 282    u8 lna_band;
 283};
 284
 285static const struct dib0070_tuning dib0070s_tuning_table[] = {
 286    {     570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */
 287    {     700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 },
 288    {     863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 },
 289    {    1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */
 290    {    1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
 291    {    2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
 292    { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */
 293};
 294
 295static const struct dib0070_tuning dib0070_tuning_table[] = {
 296    {     115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */
 297    {     179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */
 298    {     189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 },
 299    {     250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 },
 300    {     569999, 2, 1, 5,  6, 2, 2, 0x4000 | 0x0800 }, /* UHF */
 301    {     699999, 2, 0, 1,  4, 2, 2, 0x4000 | 0x0800 },
 302    {     863999, 2, 1, 1,  4, 2, 2, 0x4000 | 0x0800 },
 303    { 0xffffffff, 0, 1, 0,  2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */
 304};
 305
 306static const struct dib0070_lna_match dib0070_lna_flip_chip[] = {
 307    {     180000, 0 }, /* VHF */
 308    {     188000, 1 },
 309    {     196400, 2 },
 310    {     250000, 3 },
 311    {     550000, 0 }, /* UHF */
 312    {     590000, 1 },
 313    {     666000, 3 },
 314    {     864000, 5 },
 315    {    1500000, 0 }, /* LBAND or everything higher than UHF */
 316    {    1600000, 1 },
 317    {    2000000, 3 },
 318    { 0xffffffff, 7 },
 319};
 320
 321static const struct dib0070_lna_match dib0070_lna[] = {
 322    {     180000, 0 }, /* VHF */
 323    {     188000, 1 },
 324    {     196400, 2 },
 325    {     250000, 3 },
 326    {     550000, 2 }, /* UHF */
 327    {     650000, 3 },
 328    {     750000, 5 },
 329    {     850000, 6 },
 330    {     864000, 7 },
 331    {    1500000, 0 }, /* LBAND or everything higher than UHF */
 332    {    1600000, 1 },
 333    {    2000000, 3 },
 334    { 0xffffffff, 7 },
 335};
 336
 337#define LPF     100
 338static int dib0070_tune_digital(struct dvb_frontend *fe)
 339{
 340    struct dib0070_state *state = fe->tuner_priv;
 341
 342    const struct dib0070_tuning *tune;
 343    const struct dib0070_lna_match *lna_match;
 344
 345    enum frontend_tune_state *tune_state = &state->tune_state;
 346    int ret = 10; /* 1ms is the default delay most of the time */
 347
 348    u8  band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000);
 349    u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf);
 350
 351#ifdef CONFIG_SYS_ISDBT
 352    if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
 353                if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2)
 354                     && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
 355                    || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
 356                        && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2)))
 357                    || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
 358                        && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))))
 359                        freq += 850;
 360#endif
 361    if (state->current_rf != freq) {
 362
 363        switch (state->revision) {
 364        case DIB0070S_P1A:
 365            tune = dib0070s_tuning_table;
 366            lna_match = dib0070_lna;
 367            break;
 368        default:
 369            tune = dib0070_tuning_table;
 370            if (state->cfg->flip_chip)
 371                lna_match = dib0070_lna_flip_chip;
 372            else
 373                lna_match = dib0070_lna;
 374            break;
 375        }
 376        while (freq > tune->max_freq) /* find the right one */
 377            tune++;
 378        while (freq > lna_match->max_freq) /* find the right one */
 379            lna_match++;
 380
 381        state->current_tune_table_index = tune;
 382        state->lna_match = lna_match;
 383    }
 384
 385    if (*tune_state == CT_TUNER_START) {
 386        dprintk("Tuning for Band: %hd (%d kHz)", band, freq);
 387        if (state->current_rf != freq) {
 388                u8 REFDIV;
 389                u32 FBDiv, Rest, FREF, VCOF_kHz;
 390                u8 Den;
 391
 392                state->current_rf = freq;
 393                state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7);
 394
 395
 396                dib0070_write_reg(state, 0x17, 0x30);
 397
 398
 399                VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2;
 400
 401                switch (band) {
 402                case BAND_VHF:
 403                        REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000);
 404                        break;
 405                case BAND_FM:
 406                        REFDIV = (u8) ((state->cfg->clock_khz) / 1000);
 407                        break;
 408                default:
 409                        REFDIV = (u8) (state->cfg->clock_khz  / 10000);
 410                        break;
 411                }
 412                FREF = state->cfg->clock_khz / REFDIV;
 413
 414
 415
 416                switch (state->revision) {
 417                case DIB0070S_P1A:
 418                        FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF);
 419                        Rest  = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF;
 420                        break;
 421
 422                case DIB0070_P1G:
 423                case DIB0070_P1F:
 424                default:
 425                        FBDiv = (freq / (FREF / 2));
 426                        Rest  = 2 * freq - FBDiv * FREF;
 427                        break;
 428                }
 429
 430                if (Rest < LPF)
 431                        Rest = 0;
 432                else if (Rest < 2 * LPF)
 433                        Rest = 2 * LPF;
 434                else if (Rest > (FREF - LPF)) {
 435                        Rest = 0;
 436                        FBDiv += 1;
 437                } else if (Rest > (FREF - 2 * LPF))
 438                        Rest = FREF - 2 * LPF;
 439                Rest = (Rest * 6528) / (FREF / 10);
 440
 441                Den = 1;
 442                if (Rest > 0) {
 443                        state->lo4 |= (1 << 14) | (1 << 12);
 444                        Den = 255;
 445                }
 446
 447
 448                dib0070_write_reg(state, 0x11, (u16)FBDiv);
 449                dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV);
 450                dib0070_write_reg(state, 0x13, (u16) Rest);
 451
 452                if (state->revision == DIB0070S_P1A) {
 453
 454                        if (band == BAND_SBAND) {
 455                                dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
 456                                dib0070_write_reg(state, 0x1d, 0xFFFF);
 457                        } else
 458                                dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1);
 459                }
 460
 461                dib0070_write_reg(state, 0x20,
 462                        0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable);
 463
 464                dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF);
 465                dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest);
 466                dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1);
 467                dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv);
 468                dprintk("VCO = %hd", state->current_tune_table_index->vco_band);
 469                dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq);
 470
 471                *tune_state = CT_TUNER_STEP_0;
 472        } else { /* we are already tuned to this frequency - the configuration is correct  */
 473                ret = 50; /* wakeup time */
 474                *tune_state = CT_TUNER_STEP_5;
 475        }
 476    } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) {
 477
 478        ret = dib0070_captrim(state, tune_state);
 479
 480    } else if (*tune_state == CT_TUNER_STEP_4) {
 481        const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
 482        if (tmp != NULL) {
 483                while (freq/1000 > tmp->freq) /* find the right one */
 484                        tmp++;
 485                dib0070_write_reg(state, 0x0f,
 486                        (0 << 15) | (1 << 14) | (3 << 12)
 487                        | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7)
 488                        | (state->current_tune_table_index->wbdmux << 0));
 489                state->wbd_gain_current = tmp->wbd_gain_val;
 490        } else {
 491                        dib0070_write_reg(state, 0x0f,
 492                                          (0 << 15) | (1 << 14) | (3 << 12) | (6 << 9) | (0 << 8) | (1 << 7) | (state->current_tune_table_index->
 493                                                                                                                wbdmux << 0));
 494            state->wbd_gain_current = 6;
 495        }
 496
 497        dib0070_write_reg(state, 0x06, 0x3fff);
 498                dib0070_write_reg(state, 0x07,
 499                                  (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0));
 500        dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127));
 501        dib0070_write_reg(state, 0x0d, 0x0d80);
 502
 503
 504        dib0070_write_reg(state, 0x18,   0x07ff);
 505        dib0070_write_reg(state, 0x17, 0x0033);
 506
 507
 508        *tune_state = CT_TUNER_STEP_5;
 509    } else if (*tune_state == CT_TUNER_STEP_5) {
 510        dib0070_set_bandwidth(fe);
 511        *tune_state = CT_TUNER_STOP;
 512    } else {
 513        ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */
 514    }
 515    return ret;
 516}
 517
 518
 519static int dib0070_tune(struct dvb_frontend *fe)
 520{
 521    struct dib0070_state *state = fe->tuner_priv;
 522    uint32_t ret;
 523
 524    state->tune_state = CT_TUNER_START;
 525
 526    do {
 527        ret = dib0070_tune_digital(fe);
 528        if (ret != FE_CALLBACK_TIME_NEVER)
 529                msleep(ret/10);
 530        else
 531            break;
 532    } while (state->tune_state != CT_TUNER_STOP);
 533
 534    return 0;
 535}
 536
 537static int dib0070_wakeup(struct dvb_frontend *fe)
 538{
 539        struct dib0070_state *state = fe->tuner_priv;
 540        if (state->cfg->sleep)
 541                state->cfg->sleep(fe, 0);
 542        return 0;
 543}
 544
 545static int dib0070_sleep(struct dvb_frontend *fe)
 546{
 547        struct dib0070_state *state = fe->tuner_priv;
 548        if (state->cfg->sleep)
 549                state->cfg->sleep(fe, 1);
 550        return 0;
 551}
 552
 553u8 dib0070_get_rf_output(struct dvb_frontend *fe)
 554{
 555        struct dib0070_state *state = fe->tuner_priv;
 556        return (dib0070_read_reg(state, 0x07) >> 11) & 0x3;
 557}
 558EXPORT_SYMBOL(dib0070_get_rf_output);
 559
 560int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no)
 561{
 562        struct dib0070_state *state = fe->tuner_priv;
 563        u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff;
 564        if (no > 3)
 565                no = 3;
 566        if (no < 1)
 567                no = 1;
 568        return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11));
 569}
 570EXPORT_SYMBOL(dib0070_set_rf_output);
 571
 572static const u16 dib0070_p1f_defaults[] =
 573
 574{
 575        7, 0x02,
 576                0x0008,
 577                0x0000,
 578                0x0000,
 579                0x0000,
 580                0x0000,
 581                0x0002,
 582                0x0100,
 583
 584        3, 0x0d,
 585                0x0d80,
 586                0x0001,
 587                0x0000,
 588
 589        4, 0x11,
 590                0x0000,
 591                0x0103,
 592                0x0000,
 593                0x0000,
 594
 595        3, 0x16,
 596                0x0004 | 0x0040,
 597                0x0030,
 598                0x07ff,
 599
 600        6, 0x1b,
 601                0x4112,
 602                0xff00,
 603                0xc07f,
 604                0x0000,
 605                0x0180,
 606                0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
 607
 608        0,
 609};
 610
 611static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain)
 612{
 613    u16 tuner_en = dib0070_read_reg(state, 0x20);
 614    u16 offset;
 615
 616    dib0070_write_reg(state, 0x18, 0x07ff);
 617    dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
 618    dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0));
 619    msleep(9);
 620    offset = dib0070_read_reg(state, 0x19);
 621    dib0070_write_reg(state, 0x20, tuner_en);
 622    return offset;
 623}
 624
 625static void dib0070_wbd_offset_calibration(struct dib0070_state *state)
 626{
 627    u8 gain;
 628    for (gain = 6; gain < 8; gain++) {
 629        state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2);
 630        dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain-6]);
 631    }
 632}
 633
 634u16 dib0070_wbd_offset(struct dvb_frontend *fe)
 635{
 636    struct dib0070_state *state = fe->tuner_priv;
 637    const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
 638    u32 freq = fe->dtv_property_cache.frequency/1000;
 639
 640    if (tmp != NULL) {
 641        while (freq/1000 > tmp->freq) /* find the right one */
 642            tmp++;
 643        state->wbd_gain_current = tmp->wbd_gain_val;
 644        } else
 645        state->wbd_gain_current = 6;
 646
 647    return state->wbd_offset_3_3[state->wbd_gain_current - 6];
 648}
 649EXPORT_SYMBOL(dib0070_wbd_offset);
 650
 651#define pgm_read_word(w) (*w)
 652static int dib0070_reset(struct dvb_frontend *fe)
 653{
 654    struct dib0070_state *state = fe->tuner_priv;
 655        u16 l, r, *n;
 656
 657        HARD_RESET(state);
 658
 659
 660#ifndef FORCE_SBAND_TUNER
 661        if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
 662                state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
 663        else
 664#else
 665#warning forcing SBAND
 666#endif
 667                state->revision = DIB0070S_P1A;
 668
 669        /* P1F or not */
 670        dprintk("Revision: %x", state->revision);
 671
 672        if (state->revision == DIB0070_P1D) {
 673                dprintk("Error: this driver is not to be used meant for P1D or earlier");
 674                return -EINVAL;
 675        }
 676
 677        n = (u16 *) dib0070_p1f_defaults;
 678        l = pgm_read_word(n++);
 679        while (l) {
 680                r = pgm_read_word(n++);
 681                do {
 682                        dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
 683                        r++;
 684                } while (--l);
 685                l = pgm_read_word(n++);
 686        }
 687
 688        if (state->cfg->force_crystal_mode != 0)
 689                r = state->cfg->force_crystal_mode;
 690        else if (state->cfg->clock_khz >= 24000)
 691                r = 1;
 692        else
 693                r = 2;
 694
 695
 696        r |= state->cfg->osc_buffer_state << 3;
 697
 698        dib0070_write_reg(state, 0x10, r);
 699        dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5));
 700
 701        if (state->cfg->invert_iq) {
 702                r = dib0070_read_reg(state, 0x02) & 0xffdf;
 703                dib0070_write_reg(state, 0x02, r | (1 << 5));
 704        }
 705
 706    if (state->revision == DIB0070S_P1A)
 707        dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
 708    else
 709                dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter);
 710
 711        dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
 712
 713    dib0070_wbd_offset_calibration(state);
 714
 715    return 0;
 716}
 717
 718static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 719{
 720    struct dib0070_state *state = fe->tuner_priv;
 721
 722    *frequency = 1000 * state->current_rf;
 723    return 0;
 724}
 725
 726static int dib0070_release(struct dvb_frontend *fe)
 727{
 728        kfree(fe->tuner_priv);
 729        fe->tuner_priv = NULL;
 730        return 0;
 731}
 732
 733static const struct dvb_tuner_ops dib0070_ops = {
 734        .info = {
 735                .name           = "DiBcom DiB0070",
 736                .frequency_min  =  45000000,
 737                .frequency_max  = 860000000,
 738                .frequency_step =      1000,
 739        },
 740        .release       = dib0070_release,
 741
 742        .init          = dib0070_wakeup,
 743        .sleep         = dib0070_sleep,
 744        .set_params    = dib0070_tune,
 745
 746        .get_frequency = dib0070_get_frequency,
 747//      .get_bandwidth = dib0070_get_bandwidth
 748};
 749
 750struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
 751{
 752        struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
 753        if (state == NULL)
 754                return NULL;
 755
 756        state->cfg = cfg;
 757        state->i2c = i2c;
 758        state->fe  = fe;
 759        mutex_init(&state->i2c_buffer_lock);
 760        fe->tuner_priv = state;
 761
 762        if (dib0070_reset(fe) != 0)
 763                goto free_mem;
 764
 765        printk(KERN_INFO "DiB0070: successfully identified\n");
 766        memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
 767
 768        fe->tuner_priv = state;
 769        return fe;
 770
 771free_mem:
 772        kfree(state);
 773        fe->tuner_priv = NULL;
 774        return NULL;
 775}
 776EXPORT_SYMBOL(dib0070_attach);
 777
 778MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
 779MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
 780MODULE_LICENSE("GPL");
 781