Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
0004  *
0005  * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)
0006  *
0007  * This code is more or less generated from another driver, please
0008  * excuse some codingstyle oddities.
0009  */
0010 
0011 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0012 
0013 #include <linux/kernel.h>
0014 #include <linux/slab.h>
0015 #include <linux/i2c.h>
0016 #include <linux/mutex.h>
0017 
0018 #include <media/dvb_frontend.h>
0019 
0020 #include "dib0070.h"
0021 #include "dibx000_common.h"
0022 
0023 static int debug;
0024 module_param(debug, int, 0644);
0025 MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
0026 
0027 #define dprintk(fmt, arg...) do {                   \
0028     if (debug)                          \
0029         printk(KERN_DEBUG pr_fmt("%s: " fmt),           \
0030                __func__, ##arg);                \
0031 } while (0)
0032 
0033 #define DIB0070_P1D  0x00
0034 #define DIB0070_P1F  0x01
0035 #define DIB0070_P1G  0x03
0036 #define DIB0070S_P1A 0x02
0037 
0038 struct dib0070_state {
0039     struct i2c_adapter *i2c;
0040     struct dvb_frontend *fe;
0041     const struct dib0070_config *cfg;
0042     u16 wbd_ff_offset;
0043     u8 revision;
0044 
0045     enum frontend_tune_state tune_state;
0046     u32 current_rf;
0047 
0048     /* for the captrim binary search */
0049     s8 step;
0050     u16 adc_diff;
0051 
0052     s8 captrim;
0053     s8 fcaptrim;
0054     u16 lo4;
0055 
0056     const struct dib0070_tuning *current_tune_table_index;
0057     const struct dib0070_lna_match *lna_match;
0058 
0059     u8  wbd_gain_current;
0060     u16 wbd_offset_3_3[2];
0061 
0062     /* for the I2C transfer */
0063     struct i2c_msg msg[2];
0064     u8 i2c_write_buffer[3];
0065     u8 i2c_read_buffer[2];
0066     struct mutex i2c_buffer_lock;
0067 };
0068 
0069 static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg)
0070 {
0071     u16 ret;
0072 
0073     if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
0074         dprintk("could not acquire lock\n");
0075         return 0;
0076     }
0077 
0078     state->i2c_write_buffer[0] = reg;
0079 
0080     memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
0081     state->msg[0].addr = state->cfg->i2c_address;
0082     state->msg[0].flags = 0;
0083     state->msg[0].buf = state->i2c_write_buffer;
0084     state->msg[0].len = 1;
0085     state->msg[1].addr = state->cfg->i2c_address;
0086     state->msg[1].flags = I2C_M_RD;
0087     state->msg[1].buf = state->i2c_read_buffer;
0088     state->msg[1].len = 2;
0089 
0090     if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
0091         pr_warn("DiB0070 I2C read failed\n");
0092         ret = 0;
0093     } else
0094         ret = (state->i2c_read_buffer[0] << 8)
0095             | state->i2c_read_buffer[1];
0096 
0097     mutex_unlock(&state->i2c_buffer_lock);
0098     return ret;
0099 }
0100 
0101 static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
0102 {
0103     int ret;
0104 
0105     if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
0106         dprintk("could not acquire lock\n");
0107         return -EINVAL;
0108     }
0109     state->i2c_write_buffer[0] = reg;
0110     state->i2c_write_buffer[1] = val >> 8;
0111     state->i2c_write_buffer[2] = val & 0xff;
0112 
0113     memset(state->msg, 0, sizeof(struct i2c_msg));
0114     state->msg[0].addr = state->cfg->i2c_address;
0115     state->msg[0].flags = 0;
0116     state->msg[0].buf = state->i2c_write_buffer;
0117     state->msg[0].len = 3;
0118 
0119     if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
0120         pr_warn("DiB0070 I2C write failed\n");
0121         ret = -EREMOTEIO;
0122     } else
0123         ret = 0;
0124 
0125     mutex_unlock(&state->i2c_buffer_lock);
0126     return ret;
0127 }
0128 
0129 #define HARD_RESET(state) do { \
0130     state->cfg->sleep(state->fe, 0); \
0131     if (state->cfg->reset) { \
0132     state->cfg->reset(state->fe,1); msleep(10); \
0133     state->cfg->reset(state->fe,0); msleep(10); \
0134     } \
0135 } while (0)
0136 
0137 static int dib0070_set_bandwidth(struct dvb_frontend *fe)
0138     {
0139     struct dib0070_state *state = fe->tuner_priv;
0140     u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff;
0141 
0142     if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000)
0143         tmp |= (0 << 14);
0144     else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000)
0145         tmp |= (1 << 14);
0146     else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000)
0147         tmp |= (2 << 14);
0148     else
0149         tmp |= (3 << 14);
0150 
0151     dib0070_write_reg(state, 0x02, tmp);
0152 
0153     /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */
0154     if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) {
0155         u16 value = dib0070_read_reg(state, 0x17);
0156 
0157         dib0070_write_reg(state, 0x17, value & 0xfffc);
0158         tmp = dib0070_read_reg(state, 0x01) & 0x01ff;
0159         dib0070_write_reg(state, 0x01, tmp | (60 << 9));
0160 
0161         dib0070_write_reg(state, 0x17, value);
0162     }
0163     return 0;
0164 }
0165 
0166 static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state *tune_state)
0167 {
0168     int8_t step_sign;
0169     u16 adc;
0170     int ret = 0;
0171 
0172     if (*tune_state == CT_TUNER_STEP_0) {
0173         dib0070_write_reg(state, 0x0f, 0xed10);
0174         dib0070_write_reg(state, 0x17,    0x0034);
0175 
0176         dib0070_write_reg(state, 0x18, 0x0032);
0177         state->step = state->captrim = state->fcaptrim = 64;
0178         state->adc_diff = 3000;
0179         ret = 20;
0180 
0181         *tune_state = CT_TUNER_STEP_1;
0182     } else if (*tune_state == CT_TUNER_STEP_1) {
0183         state->step /= 2;
0184         dib0070_write_reg(state, 0x14, state->lo4 | state->captrim);
0185         ret = 15;
0186 
0187         *tune_state = CT_TUNER_STEP_2;
0188     } else if (*tune_state == CT_TUNER_STEP_2) {
0189 
0190         adc = dib0070_read_reg(state, 0x19);
0191 
0192         dprintk("CAPTRIM=%d; ADC = %hd (ADC) & %dmV\n", state->captrim,
0193             adc, (u32)adc * (u32)1800 / (u32)1024);
0194 
0195         if (adc >= 400) {
0196             adc -= 400;
0197             step_sign = -1;
0198         } else {
0199             adc = 400 - adc;
0200             step_sign = 1;
0201         }
0202 
0203         if (adc < state->adc_diff) {
0204             dprintk("CAPTRIM=%d is closer to target (%hd/%hd)\n",
0205                 state->captrim, adc, state->adc_diff);
0206             state->adc_diff = adc;
0207             state->fcaptrim = state->captrim;
0208         }
0209         state->captrim += (step_sign * state->step);
0210 
0211         if (state->step >= 1)
0212             *tune_state = CT_TUNER_STEP_1;
0213         else
0214             *tune_state = CT_TUNER_STEP_3;
0215 
0216     } else if (*tune_state == CT_TUNER_STEP_3) {
0217         dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim);
0218         dib0070_write_reg(state, 0x18, 0x07ff);
0219         *tune_state = CT_TUNER_STEP_4;
0220     }
0221 
0222     return ret;
0223 }
0224 
0225 static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
0226 {
0227     struct dib0070_state *state = fe->tuner_priv;
0228     u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
0229 
0230     dprintk("CTRL_LO5: 0x%x\n", lo5);
0231     return dib0070_write_reg(state, 0x15, lo5);
0232 }
0233 
0234 void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)
0235 {
0236     struct dib0070_state *state = fe->tuner_priv;
0237 
0238     if (open) {
0239         dib0070_write_reg(state, 0x1b, 0xff00);
0240         dib0070_write_reg(state, 0x1a, 0x0000);
0241     } else {
0242         dib0070_write_reg(state, 0x1b, 0x4112);
0243         if (state->cfg->vga_filter != 0) {
0244             dib0070_write_reg(state, 0x1a, state->cfg->vga_filter);
0245             dprintk("vga filter register is set to %x\n", state->cfg->vga_filter);
0246         } else
0247             dib0070_write_reg(state, 0x1a, 0x0009);
0248     }
0249 }
0250 
0251 EXPORT_SYMBOL(dib0070_ctrl_agc_filter);
0252 struct dib0070_tuning {
0253     u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
0254     u8 switch_trim;
0255     u8 vco_band;
0256     u8 hfdiv;
0257     u8 vco_multi;
0258     u8 presc;
0259     u8 wbdmux;
0260     u16 tuner_enable;
0261 };
0262 
0263 struct dib0070_lna_match {
0264     u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
0265     u8 lna_band;
0266 };
0267 
0268 static const struct dib0070_tuning dib0070s_tuning_table[] = {
0269     {     570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */
0270     {     700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 },
0271     {     863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 },
0272     {    1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */
0273     {    1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
0274     {    2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
0275     { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */
0276 };
0277 
0278 static const struct dib0070_tuning dib0070_tuning_table[] = {
0279     {     115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */
0280     {     179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */
0281     {     189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 },
0282     {     250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 },
0283     {     569999, 2, 1, 5,  6, 2, 2, 0x4000 | 0x0800 }, /* UHF */
0284     {     699999, 2, 0, 1,  4, 2, 2, 0x4000 | 0x0800 },
0285     {     863999, 2, 1, 1,  4, 2, 2, 0x4000 | 0x0800 },
0286     { 0xffffffff, 0, 1, 0,  2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */
0287 };
0288 
0289 static const struct dib0070_lna_match dib0070_lna_flip_chip[] = {
0290     {     180000, 0 }, /* VHF */
0291     {     188000, 1 },
0292     {     196400, 2 },
0293     {     250000, 3 },
0294     {     550000, 0 }, /* UHF */
0295     {     590000, 1 },
0296     {     666000, 3 },
0297     {     864000, 5 },
0298     {    1500000, 0 }, /* LBAND or everything higher than UHF */
0299     {    1600000, 1 },
0300     {    2000000, 3 },
0301     { 0xffffffff, 7 },
0302 };
0303 
0304 static const struct dib0070_lna_match dib0070_lna[] = {
0305     {     180000, 0 }, /* VHF */
0306     {     188000, 1 },
0307     {     196400, 2 },
0308     {     250000, 3 },
0309     {     550000, 2 }, /* UHF */
0310     {     650000, 3 },
0311     {     750000, 5 },
0312     {     850000, 6 },
0313     {     864000, 7 },
0314     {    1500000, 0 }, /* LBAND or everything higher than UHF */
0315     {    1600000, 1 },
0316     {    2000000, 3 },
0317     { 0xffffffff, 7 },
0318 };
0319 
0320 #define LPF 100
0321 static int dib0070_tune_digital(struct dvb_frontend *fe)
0322 {
0323     struct dib0070_state *state = fe->tuner_priv;
0324 
0325     const struct dib0070_tuning *tune;
0326     const struct dib0070_lna_match *lna_match;
0327 
0328     enum frontend_tune_state *tune_state = &state->tune_state;
0329     int ret = 10; /* 1ms is the default delay most of the time */
0330 
0331     u8  band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000);
0332     u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf);
0333 
0334 #ifdef CONFIG_SYS_ISDBT
0335     if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
0336             if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2)
0337             && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
0338             || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
0339                 && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2)))
0340             || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
0341                 && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))))
0342                 freq += 850;
0343 #endif
0344     if (state->current_rf != freq) {
0345 
0346         switch (state->revision) {
0347         case DIB0070S_P1A:
0348         tune = dib0070s_tuning_table;
0349         lna_match = dib0070_lna;
0350         break;
0351         default:
0352         tune = dib0070_tuning_table;
0353         if (state->cfg->flip_chip)
0354             lna_match = dib0070_lna_flip_chip;
0355         else
0356             lna_match = dib0070_lna;
0357         break;
0358         }
0359         while (freq > tune->max_freq) /* find the right one */
0360             tune++;
0361         while (freq > lna_match->max_freq) /* find the right one */
0362             lna_match++;
0363 
0364         state->current_tune_table_index = tune;
0365         state->lna_match = lna_match;
0366     }
0367 
0368     if (*tune_state == CT_TUNER_START) {
0369         dprintk("Tuning for Band: %d (%d kHz)\n", band, freq);
0370         if (state->current_rf != freq) {
0371             u8 REFDIV;
0372             u32 FBDiv, Rest, FREF, VCOF_kHz;
0373             u8 Den;
0374 
0375             state->current_rf = freq;
0376             state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7);
0377 
0378 
0379             dib0070_write_reg(state, 0x17, 0x30);
0380 
0381 
0382             VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2;
0383 
0384             switch (band) {
0385             case BAND_VHF:
0386                 REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000);
0387                 break;
0388             case BAND_FM:
0389                 REFDIV = (u8) ((state->cfg->clock_khz) / 1000);
0390                 break;
0391             default:
0392                 REFDIV = (u8) (state->cfg->clock_khz  / 10000);
0393                 break;
0394             }
0395             FREF = state->cfg->clock_khz / REFDIV;
0396 
0397 
0398 
0399             switch (state->revision) {
0400             case DIB0070S_P1A:
0401                 FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF);
0402                 Rest  = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF;
0403                 break;
0404 
0405             case DIB0070_P1G:
0406             case DIB0070_P1F:
0407             default:
0408                 FBDiv = (freq / (FREF / 2));
0409                 Rest  = 2 * freq - FBDiv * FREF;
0410                 break;
0411             }
0412 
0413             if (Rest < LPF)
0414                 Rest = 0;
0415             else if (Rest < 2 * LPF)
0416                 Rest = 2 * LPF;
0417             else if (Rest > (FREF - LPF)) {
0418                 Rest = 0;
0419                 FBDiv += 1;
0420             } else if (Rest > (FREF - 2 * LPF))
0421                 Rest = FREF - 2 * LPF;
0422             Rest = (Rest * 6528) / (FREF / 10);
0423 
0424             Den = 1;
0425             if (Rest > 0) {
0426                 state->lo4 |= (1 << 14) | (1 << 12);
0427                 Den = 255;
0428             }
0429 
0430 
0431             dib0070_write_reg(state, 0x11, (u16)FBDiv);
0432             dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV);
0433             dib0070_write_reg(state, 0x13, (u16) Rest);
0434 
0435             if (state->revision == DIB0070S_P1A) {
0436 
0437                 if (band == BAND_SBAND) {
0438                     dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
0439                     dib0070_write_reg(state, 0x1d, 0xFFFF);
0440                 } else
0441                     dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1);
0442             }
0443 
0444             dib0070_write_reg(state, 0x20,
0445                 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable);
0446 
0447             dprintk("REFDIV: %u, FREF: %d\n", REFDIV, FREF);
0448             dprintk("FBDIV: %d, Rest: %d\n", FBDiv, Rest);
0449             dprintk("Num: %u, Den: %u, SD: %d\n", (u16)Rest, Den,
0450                 (state->lo4 >> 12) & 0x1);
0451             dprintk("HFDIV code: %u\n",
0452                 state->current_tune_table_index->hfdiv);
0453             dprintk("VCO = %u\n",
0454                 state->current_tune_table_index->vco_band);
0455             dprintk("VCOF: ((%u*%d) << 1))\n",
0456                 state->current_tune_table_index->vco_multi,
0457                 freq);
0458 
0459             *tune_state = CT_TUNER_STEP_0;
0460         } else { /* we are already tuned to this frequency - the configuration is correct  */
0461             ret = 50; /* wakeup time */
0462             *tune_state = CT_TUNER_STEP_5;
0463         }
0464     } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) {
0465 
0466         ret = dib0070_captrim(state, tune_state);
0467 
0468     } else if (*tune_state == CT_TUNER_STEP_4) {
0469         const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
0470         if (tmp != NULL) {
0471             while (freq/1000 > tmp->freq) /* find the right one */
0472                 tmp++;
0473             dib0070_write_reg(state, 0x0f,
0474                 (0 << 15) | (1 << 14) | (3 << 12)
0475                 | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7)
0476                 | (state->current_tune_table_index->wbdmux << 0));
0477             state->wbd_gain_current = tmp->wbd_gain_val;
0478         } else {
0479             dib0070_write_reg(state, 0x0f,
0480                       (0 << 15) | (1 << 14) | (3 << 12)
0481                       | (6 << 9) | (0 << 8) | (1 << 7)
0482                       | (state->current_tune_table_index->wbdmux << 0));
0483             state->wbd_gain_current = 6;
0484         }
0485 
0486         dib0070_write_reg(state, 0x06, 0x3fff);
0487         dib0070_write_reg(state, 0x07,
0488                   (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0));
0489         dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127));
0490         dib0070_write_reg(state, 0x0d, 0x0d80);
0491 
0492 
0493         dib0070_write_reg(state, 0x18,   0x07ff);
0494         dib0070_write_reg(state, 0x17, 0x0033);
0495 
0496 
0497         *tune_state = CT_TUNER_STEP_5;
0498     } else if (*tune_state == CT_TUNER_STEP_5) {
0499         dib0070_set_bandwidth(fe);
0500         *tune_state = CT_TUNER_STOP;
0501     } else {
0502         ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */
0503     }
0504     return ret;
0505 }
0506 
0507 
0508 static int dib0070_tune(struct dvb_frontend *fe)
0509 {
0510     struct dib0070_state *state = fe->tuner_priv;
0511     uint32_t ret;
0512 
0513     state->tune_state = CT_TUNER_START;
0514 
0515     do {
0516         ret = dib0070_tune_digital(fe);
0517         if (ret != FE_CALLBACK_TIME_NEVER)
0518             msleep(ret/10);
0519         else
0520         break;
0521     } while (state->tune_state != CT_TUNER_STOP);
0522 
0523     return 0;
0524 }
0525 
0526 static int dib0070_wakeup(struct dvb_frontend *fe)
0527 {
0528     struct dib0070_state *state = fe->tuner_priv;
0529     if (state->cfg->sleep)
0530         state->cfg->sleep(fe, 0);
0531     return 0;
0532 }
0533 
0534 static int dib0070_sleep(struct dvb_frontend *fe)
0535 {
0536     struct dib0070_state *state = fe->tuner_priv;
0537     if (state->cfg->sleep)
0538         state->cfg->sleep(fe, 1);
0539     return 0;
0540 }
0541 
0542 u8 dib0070_get_rf_output(struct dvb_frontend *fe)
0543 {
0544     struct dib0070_state *state = fe->tuner_priv;
0545     return (dib0070_read_reg(state, 0x07) >> 11) & 0x3;
0546 }
0547 EXPORT_SYMBOL(dib0070_get_rf_output);
0548 
0549 int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no)
0550 {
0551     struct dib0070_state *state = fe->tuner_priv;
0552     u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff;
0553     if (no > 3)
0554         no = 3;
0555     if (no < 1)
0556         no = 1;
0557     return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11));
0558 }
0559 EXPORT_SYMBOL(dib0070_set_rf_output);
0560 
0561 static const u16 dib0070_p1f_defaults[] =
0562 
0563 {
0564     7, 0x02,
0565         0x0008,
0566         0x0000,
0567         0x0000,
0568         0x0000,
0569         0x0000,
0570         0x0002,
0571         0x0100,
0572 
0573     3, 0x0d,
0574         0x0d80,
0575         0x0001,
0576         0x0000,
0577 
0578     4, 0x11,
0579         0x0000,
0580         0x0103,
0581         0x0000,
0582         0x0000,
0583 
0584     3, 0x16,
0585         0x0004 | 0x0040,
0586         0x0030,
0587         0x07ff,
0588 
0589     6, 0x1b,
0590         0x4112,
0591         0xff00,
0592         0xc07f,
0593         0x0000,
0594         0x0180,
0595         0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
0596 
0597     0,
0598 };
0599 
0600 static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain)
0601 {
0602     u16 tuner_en = dib0070_read_reg(state, 0x20);
0603     u16 offset;
0604 
0605     dib0070_write_reg(state, 0x18, 0x07ff);
0606     dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
0607     dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0));
0608     msleep(9);
0609     offset = dib0070_read_reg(state, 0x19);
0610     dib0070_write_reg(state, 0x20, tuner_en);
0611     return offset;
0612 }
0613 
0614 static void dib0070_wbd_offset_calibration(struct dib0070_state *state)
0615 {
0616     u8 gain;
0617     for (gain = 6; gain < 8; gain++) {
0618         state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2);
0619         dprintk("Gain: %d, WBDOffset (3.3V) = %hd\n", gain, state->wbd_offset_3_3[gain-6]);
0620     }
0621 }
0622 
0623 u16 dib0070_wbd_offset(struct dvb_frontend *fe)
0624 {
0625     struct dib0070_state *state = fe->tuner_priv;
0626     const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
0627     u32 freq = fe->dtv_property_cache.frequency/1000;
0628 
0629     if (tmp != NULL) {
0630         while (freq/1000 > tmp->freq) /* find the right one */
0631             tmp++;
0632         state->wbd_gain_current = tmp->wbd_gain_val;
0633     } else
0634         state->wbd_gain_current = 6;
0635 
0636     return state->wbd_offset_3_3[state->wbd_gain_current - 6];
0637 }
0638 EXPORT_SYMBOL(dib0070_wbd_offset);
0639 
0640 #define pgm_read_word(w) (*w)
0641 static int dib0070_reset(struct dvb_frontend *fe)
0642 {
0643     struct dib0070_state *state = fe->tuner_priv;
0644     u16 l, r, *n;
0645 
0646     HARD_RESET(state);
0647 
0648 
0649 #ifndef FORCE_SBAND_TUNER
0650     if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
0651         state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
0652     else
0653 #else
0654 #warning forcing SBAND
0655 #endif
0656     state->revision = DIB0070S_P1A;
0657 
0658     /* P1F or not */
0659     dprintk("Revision: %x\n", state->revision);
0660 
0661     if (state->revision == DIB0070_P1D) {
0662         dprintk("Error: this driver is not to be used meant for P1D or earlier\n");
0663         return -EINVAL;
0664     }
0665 
0666     n = (u16 *) dib0070_p1f_defaults;
0667     l = pgm_read_word(n++);
0668     while (l) {
0669         r = pgm_read_word(n++);
0670         do {
0671             dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
0672             r++;
0673         } while (--l);
0674         l = pgm_read_word(n++);
0675     }
0676 
0677     if (state->cfg->force_crystal_mode != 0)
0678         r = state->cfg->force_crystal_mode;
0679     else if (state->cfg->clock_khz >= 24000)
0680         r = 1;
0681     else
0682         r = 2;
0683 
0684 
0685     r |= state->cfg->osc_buffer_state << 3;
0686 
0687     dib0070_write_reg(state, 0x10, r);
0688     dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5));
0689 
0690     if (state->cfg->invert_iq) {
0691         r = dib0070_read_reg(state, 0x02) & 0xffdf;
0692         dib0070_write_reg(state, 0x02, r | (1 << 5));
0693     }
0694 
0695     if (state->revision == DIB0070S_P1A)
0696         dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
0697     else
0698         dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump,
0699                      state->cfg->enable_third_order_filter);
0700 
0701     dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
0702 
0703     dib0070_wbd_offset_calibration(state);
0704 
0705     return 0;
0706 }
0707 
0708 static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency)
0709 {
0710     struct dib0070_state *state = fe->tuner_priv;
0711 
0712     *frequency = 1000 * state->current_rf;
0713     return 0;
0714 }
0715 
0716 static void dib0070_release(struct dvb_frontend *fe)
0717 {
0718     kfree(fe->tuner_priv);
0719     fe->tuner_priv = NULL;
0720 }
0721 
0722 static const struct dvb_tuner_ops dib0070_ops = {
0723     .info = {
0724         .name              = "DiBcom DiB0070",
0725         .frequency_min_hz  =  45 * MHz,
0726         .frequency_max_hz  = 860 * MHz,
0727         .frequency_step_hz =   1 * kHz,
0728     },
0729     .release       = dib0070_release,
0730 
0731     .init          = dib0070_wakeup,
0732     .sleep         = dib0070_sleep,
0733     .set_params    = dib0070_tune,
0734 
0735     .get_frequency = dib0070_get_frequency,
0736 //      .get_bandwidth = dib0070_get_bandwidth
0737 };
0738 
0739 struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
0740 {
0741     struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
0742     if (state == NULL)
0743         return NULL;
0744 
0745     state->cfg = cfg;
0746     state->i2c = i2c;
0747     state->fe  = fe;
0748     mutex_init(&state->i2c_buffer_lock);
0749     fe->tuner_priv = state;
0750 
0751     if (dib0070_reset(fe) != 0)
0752         goto free_mem;
0753 
0754     pr_info("DiB0070: successfully identified\n");
0755     memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
0756 
0757     fe->tuner_priv = state;
0758     return fe;
0759 
0760 free_mem:
0761     kfree(state);
0762     fe->tuner_priv = NULL;
0763     return NULL;
0764 }
0765 EXPORT_SYMBOL(dib0070_attach);
0766 
0767 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
0768 MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
0769 MODULE_LICENSE("GPL");