Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/media/usb/dvb-usb/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 142 kB image not shown  

Quelle  dib0700_devices.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
 *
 *  Copyright (C) 2005-9 DiBcom, SA et al
 */

#include "dib0700.h"

#include "dib3000mc.h"
#include "dib7000m.h"
#include "dib7000p.h"
#include "dib8000.h"
#include "dib9000.h"
#include "mt2060.h"
#include "mt2266.h"
#include "xc2028.h"
#include "xc5000.h"
#include "xc4000.h"
#include "s5h1411.h"
#include "dib0070.h"
#include "dib0090.h"
#include "lgdt3305.h"
#include "mxl5007t.h"
#include "mn88472.h"
#include "tda18250.h"


static int force_lna_activation;
module_param(force_lna_activation, int, 0644);
MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifier(s) (LNA), if applicable for the device (default: 0=automatic/off).");

struct dib0700_adapter_state {
 int (*set_param_save) (struct dvb_frontend *);
 const struct firmware *frontend_firmware;
 struct dib7000p_ops dib7000p_ops;
 struct dib8000_ops dib8000_ops;
};

/* Hauppauge Nova-T 500 (aka Bristol)
 *  has a LNA on GPIO0 which is enabled by setting 1 */

static struct mt2060_config bristol_mt2060_config[2] = {
 {
  .i2c_address = 0x60,
  .clock_out   = 3,
 }, {
  .i2c_address = 0x61,
 }
};


static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = {
 .band_caps = BAND_VHF | BAND_UHF,
 .setup     = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0),

 .agc1_max = 42598,
 .agc1_min = 17694,
 .agc2_max = 45875,
 .agc2_min = 0,

 .agc1_pt1 = 0,
 .agc1_pt2 = 59,

 .agc1_slope1 = 0,
 .agc1_slope2 = 69,

 .agc2_pt1 = 0,
 .agc2_pt2 = 59,

 .agc2_slope1 = 111,
 .agc2_slope2 = 28,
};

static struct dib3000mc_config bristol_dib3000mc_config[2] = {
 { .agc          = &bristol_dib3000p_mt2060_agc_config,
  .max_time     = 0x196,
  .ln_adc_level = 0x1cc7,
  .output_mpeg2_in_188_bytes = 1,
 },
 { .agc          = &bristol_dib3000p_mt2060_agc_config,
  .max_time     = 0x196,
  .ln_adc_level = 0x1cc7,
  .output_mpeg2_in_188_bytes = 1,
 }
};

static int bristol_frontend_attach(struct dvb_usb_adapter *adap)
{
 struct dib0700_state *st = adap->dev->priv;
 if (adap->id == 0) {
  dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 0); msleep(10);
  dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 1); msleep(10);
  dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
  dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10);

  if (force_lna_activation)
   dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
  else
   dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0);

  if (dib3000mc_i2c_enumeration(&adap->dev->i2c_adap, 2, DEFAULT_DIB3000P_I2C_ADDRESS, bristol_dib3000mc_config) != 0) {
   dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10);
   return -ENODEV;
  }
 }
 st->mt2060_if1[adap->id] = 1220;
 return (adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap,
  (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0;
}

static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval)
{
 struct i2c_msg msg[2] = {
  { .addr = 0x50, .flags = 0,        .buf = &adrs, .len = 1 },
  { .addr = 0x50, .flags = I2C_M_RD, .buf = pval,  .len = 1 },
 };
 if (i2c_transfer(adap, msg, 2) != 2) return -EREMOTEIO;
 return 0;
}

static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
{
 struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
 struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1);
 s8 a;
 int if1=1220;
 if (adap->dev->udev->descriptor.idVendor  == cpu_to_le16(USB_VID_HAUPPAUGE) &&
  adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_500_2)) {
  if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a;
 }
 return dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c,
     &bristol_mt2060_config[adap->id], if1) == NULL ?
     -ENODEV : 0;
}

/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */

/* MT226x */
static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = {
 {
  BAND_UHF,

  /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */

  (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8)
     | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),

  1130,
  21,

  0,
  118,

  0,
  3530,
  1,
  0,

  65535,
  33770,
  65535,
  23592,

  0,
  62,
  255,
  64,
  64,
  132,
  192,
  80,
  80,

  17,
  27,
  23,
  51,

  1,
 }, {
  BAND_VHF | BAND_LBAND,

  /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */

  (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8)
     | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),

  2372,
  21,

  0,
  118,

  0,
  3530,
  1,
  0,

  65535,
  0,
  65535,
  23592,

  0,
  128,
  128,
  128,
  0,
  128,
  253,
  81,
  0,

  17,
  27,
  23,
  51,

  1,
 }
};

static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = {
 .internal = 60000,
 .sampling = 30000,
 .pll_prediv = 1,
 .pll_ratio = 8,
 .pll_range = 3,
 .pll_reset = 1,
 .pll_bypass = 0,
 .enable_refdiv = 0,
 .bypclk_div = 0,
 .IO_CLK_en_core = 1,
 .ADClkSrc = 1,
 .modulo = 2,
 .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
 .ifreq = 0,
 .timf = 20452225,
};

static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = {
 { .output_mpeg2_in_188_bytes = 1,
  .hostbus_diversity = 1,
  .tuner_is_baseband = 1,

  .agc_config_count = 2,
  .agc = stk7700d_7000p_mt2266_agc_config,
  .bw  = &stk7700d_mt2266_pll_config,

  .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
  .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
  .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
 },
 { .output_mpeg2_in_188_bytes = 1,
  .hostbus_diversity = 1,
  .tuner_is_baseband = 1,

  .agc_config_count = 2,
  .agc = stk7700d_7000p_mt2266_agc_config,
  .bw  = &stk7700d_mt2266_pll_config,

  .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
  .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
  .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
 }
};

static struct mt2266_config stk7700d_mt2266_config[2] = {
 { .i2c_address = 0x60
 },
 { .i2c_address = 0x60
 }
};

static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap)
{
 struct dib0700_adapter_state *state = adap->priv;

 if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
  return -ENODEV;

 if (adap->id == 0) {
  dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
  msleep(10);
  dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
  dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
  dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
  dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
  msleep(10);
  dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
  msleep(10);
  if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
          stk7700d_dib7000p_mt2266_config)
      != 0) {
   err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__);
   dvb_detach(state->dib7000p_ops.set_wbd_ref);
   return -ENODEV;
  }
 }

 adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap,
      0x80 + (adap->id << 1),
      &stk7700d_dib7000p_mt2266_config[adap->id]);

 return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}

static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
{
 struct dib0700_adapter_state *state = adap->priv;

 if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
  return -ENODEV;

 if (adap->id == 0) {
  dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
  msleep(10);
  dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
  dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
  dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
  dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
  msleep(10);
  dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
  msleep(10);
  dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
  if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 2, 18,
          stk7700d_dib7000p_mt2266_config)
      != 0) {
   err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__);
   dvb_detach(state->dib7000p_ops.set_wbd_ref);
   return -ENODEV;
  }
 }

 adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap,
      0x80 + (adap->id << 1),
      &stk7700d_dib7000p_mt2266_config[adap->id]);

 return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}

static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
{
 struct i2c_adapter *tun_i2c;
 struct dib0700_adapter_state *state = adap->priv;

 tun_i2c = state->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe,
         DIBX000_I2C_INTERFACE_TUNER, 1);
 return dvb_attach(mt2266_attach, adap->fe_adap[0].fe, tun_i2c,
  &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;
}

/* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */
static struct dibx000_agc_config xc3028_agc_config = {
 .band_caps = BAND_VHF | BAND_UHF,
 /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */

 .setup = (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
 .inv_gain = 712,
 .time_stabiliz = 21,
 .alpha_level = 0,
 .thlock = 118,
 .wbd_inv = 0,
 .wbd_ref = 2867,
 .wbd_sel = 0,
 .wbd_alpha = 2,
 .agc1_max = 0,
 .agc1_min = 0,
 .agc2_max = 39718,
 .agc2_min = 9930,
 .agc1_pt1 = 0,
 .agc1_pt2 = 0,
 .agc1_pt3 = 0,
 .agc1_slope1 = 0,
 .agc1_slope2 = 0,
 .agc2_pt1 = 0,
 .agc2_pt2 = 128,
 .agc2_slope1 = 29,
 .agc2_slope2 = 29,
 .alpha_mant = 17,
 .alpha_exp = 27,
 .beta_mant = 23,
 .beta_exp = 51,
 .perform_agc_softsplit = 1,
};

/* PLL Configuration for COFDM BW_MHz = 8.00 with external clock = 30.00 */
static struct dibx000_bandwidth_config xc3028_bw_config = {
 .internal = 60000,
 .sampling = 30000,
 .pll_prediv = 1,
 .pll_ratio = 8,
 .pll_range = 3,
 .pll_reset = 1,
 .pll_bypass = 0,
 .enable_refdiv = 0,
 .bypclk_div = 0,
 .IO_CLK_en_core = 1,
 .ADClkSrc = 1,
 .modulo = 0,
 .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
 .ifreq = (1 << 25) | 5816102,  /* ifreq = 5.200000 MHz */
 .timf = 20452225,
 .xtal_hz = 30000000,
};

static struct dib7000p_config stk7700ph_dib7700_xc3028_config = {
 .output_mpeg2_in_188_bytes = 1,
 .tuner_is_baseband = 1,

 .agc_config_count = 1,
 .agc = &xc3028_agc_config,
 .bw  = &xc3028_bw_config,

 .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
 .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
 .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
};

static int stk7700ph_xc3028_callback(void *ptr, int component,
         int command, int arg)
{
 struct dvb_usb_adapter *adap = ptr;
 struct dib0700_adapter_state *state = adap->priv;

 switch (command) {
 case XC2028_TUNER_RESET:
  /* Send the tuner in then out of reset */
  state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 0);
  msleep(10);
  state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
  break;
 case XC2028_RESET_CLK:
 case XC2028_I2C_FLUSH:
  break;
 default:
  err("%s: unknown command %d, arg %d\n", __func__,
   command, arg);
  return -EINVAL;
 }
 return 0;
}

static struct xc2028_ctrl stk7700ph_xc3028_ctrl = {
 .fname = XC2028_DEFAULT_FIRMWARE,
 .max_len = 64,
 .demod = XC3028_FE_DIBCOM52,
};

static struct xc2028_config stk7700ph_xc3028_config = {
 .i2c_addr = 0x61,
 .ctrl = &stk7700ph_xc3028_ctrl,
};

static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap)
{
 struct usb_device_descriptor *desc = &adap->dev->udev->descriptor;
 struct dib0700_adapter_state *state = adap->priv;

 if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
  return -ENODEV;

 if (desc->idVendor  == cpu_to_le16(USB_VID_PINNACLE) &&
     desc->idProduct == cpu_to_le16(USB_PID_PINNACLE_EXPRESSCARD_320CX))
  dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
 else
  dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
 msleep(20);
 dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
 msleep(10);
 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
 msleep(20);
 dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
 msleep(10);

 if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
         &stk7700ph_dib7700_xc3028_config) != 0) {
  err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n",
      __func__);
  dvb_detach(state->dib7000p_ops.set_wbd_ref);
  return -ENODEV;
 }

 adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80,
  &stk7700ph_dib7700_xc3028_config);

 return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}

static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap)
{
 struct i2c_adapter *tun_i2c;
 struct dib0700_adapter_state *state = adap->priv;

 tun_i2c = state->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe,
  DIBX000_I2C_INTERFACE_TUNER, 1);

 stk7700ph_xc3028_config.i2c_adap = tun_i2c;

 /* FIXME: generalize & move to common area */
 adap->fe_adap[0].fe->callback = stk7700ph_xc3028_callback;

 return dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &stk7700ph_xc3028_config)
  == NULL ? -ENODEV : 0;
}

#define DEFAULT_RC_INTERVAL 50

/*
 * This function is used only when firmware is < 1.20 version. Newer
 * firmwares use bulk mode, with functions implemented at dib0700_core,
 * at dib0700_rc_urb_completion()
 */

static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
{
 enum rc_proto protocol;
 u32 scancode;
 u8 toggle;
 int i;
 struct dib0700_state *st = d->priv;

 if (st->fw_version >= 0x10200) {
  /* For 1.20 firmware , We need to keep the RC polling
   callback so we can reuse the input device setup in
   dvb-usb-remote.c.  However, the actual work is being done
   in the bulk URB completion handler. */

  return 0;
 }

 st->buf[0] = REQUEST_POLL_RC;
 st->buf[1] = 0;

 i = dib0700_ctrl_rd(d, st->buf, 2, st->buf, 4);
 if (i <= 0) {
  err("RC Query Failed");
  return -EIO;
 }

 /* losing half of KEY_0 events from Philipps rc5 remotes.. */
 if (st->buf[0] == 0 && st->buf[1] == 0
     && st->buf[2] == 0 && st->buf[3] == 0)
  return 0;

 /* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)st->buf[3 - 2],(int)st->buf[3 - 3],(int)st->buf[3 - 1],(int)st->buf[3]);  */

 dib0700_rc_setup(d, NULL); /* reset ir sensor data to prevent false events */

 switch (d->props.rc.core.protocol) {
 case RC_PROTO_BIT_NEC:
  /* NEC protocol sends repeat code as 0 0 0 FF */
  if ((st->buf[3 - 2] == 0x00) && (st->buf[3 - 3] == 0x00) &&
      (st->buf[3] == 0xff)) {
   rc_repeat(d->rc_dev);
   return 0;
  }

  protocol = RC_PROTO_NEC;
  scancode = RC_SCANCODE_NEC(st->buf[3 - 2], st->buf[3 - 3]);
  toggle = 0;
  break;

 default:
  /* RC-5 protocol changes toggle bit on new keypress */
  protocol = RC_PROTO_RC5;
  scancode = RC_SCANCODE_RC5(st->buf[3 - 2], st->buf[3 - 3]);
  toggle = st->buf[3 - 1];
  break;
 }

 rc_keydown(d->rc_dev, protocol, scancode, toggle);
 return 0;
}

/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
 BAND_UHF | BAND_VHF,

 /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */

 (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
 | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),

 712,
 41,

 0,
 118,

 0,
 4095,
 0,
 0,

 42598,
 17694,
 45875,
 2621,
 0,
 76,
 139,
 52,
 59,
 107,
 172,
 57,
 70,

 21,
 25,
 28,
 48,

 1,
 {  0,
    107,
    51800,
    24700
 },
};

static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = {
 .band_caps = BAND_UHF | BAND_VHF,
 /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */

 .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
 .inv_gain = 712,
 .time_stabiliz = 41,
 .alpha_level = 0,
 .thlock = 118,
 .wbd_inv = 0,
 .wbd_ref = 4095,
 .wbd_sel = 0,
 .wbd_alpha = 0,
 .agc1_max = 42598,
 .agc1_min = 16384,
 .agc2_max = 42598,
 .agc2_min = 0,
 .agc1_pt1 = 0,
 .agc1_pt2 = 137,
 .agc1_pt3 = 255,
 .agc1_slope1 = 0,
 .agc1_slope2 = 255,
 .agc2_pt1 = 0,
 .agc2_pt2 = 0,
 .agc2_slope1 = 0,
 .agc2_slope2 = 41,
 .alpha_mant = 15,
 .alpha_exp = 25,
 .beta_mant = 28,
 .beta_exp = 48,
 .perform_agc_softsplit = 0,
};

static struct dibx000_bandwidth_config stk7700p_pll_config = {
 .internal = 60000,
 .sampling = 30000,
 .pll_prediv = 1,
 .pll_ratio = 8,
 .pll_range = 3,
 .pll_reset = 1,
 .pll_bypass = 0,
 .enable_refdiv = 0,
 .bypclk_div = 0,
 .IO_CLK_en_core = 1,
 .ADClkSrc = 1,
 .modulo = 0,
 .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
 .ifreq = 60258167,
 .timf = 20452225,
 .xtal_hz = 30000000,
};

static struct dib7000m_config stk7700p_dib7000m_config = {
 .dvbt_mode = 1,
 .output_mpeg2_in_188_bytes = 1,
 .quartz_direct = 1,

 .agc_config_count = 1,
 .agc = &stk7700p_7000m_mt2060_agc_config,
 .bw  = &stk7700p_pll_config,

 .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
 .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
 .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
};

static struct dib7000p_config stk7700p_dib7000p_config = {
 .output_mpeg2_in_188_bytes = 1,

 .agc_config_count = 1,
 .agc = &stk7700p_7000p_mt2060_agc_config,
 .bw  = &stk7700p_pll_config,

 .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
 .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
 .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
};

static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap)
{
 struct dib0700_state *st = adap->dev->priv;
 struct dib0700_adapter_state *state = adap->priv;

 if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
  return -ENODEV;

 /* unless there is no real power management in DVB - we leave the device on GPIO6 */

 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
 dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 0); msleep(50);

 dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 1); msleep(10);
 dib0700_set_gpio(adap->dev, GPIO9,  GPIO_OUT, 1);

 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
 dib0700_ctrl_clock(adap->dev, 72, 1);
 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(100);

 dib0700_set_gpio(adap->dev,  GPIO0, GPIO_OUT, 1);

 st->mt2060_if1[0] = 1220;

 if (state->dib7000p_ops.dib7000pc_detection(&adap->dev->i2c_adap)) {
  adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config);
  st->is_dib7000pc = 1;
 } else {
  memset(&state->dib7000p_ops, 0, sizeof(state->dib7000p_ops));
  adap->fe_adap[0].fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config);
 }

 return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}

static struct mt2060_config stk7700p_mt2060_config = {
 0x60
};

static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
{
 struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
 struct dib0700_state *st = adap->dev->priv;
 struct i2c_adapter *tun_i2c;
 struct dib0700_adapter_state *state = adap->priv;
 s8 a;
 int if1=1220;

 if (adap->dev->udev->descriptor.idVendor  == cpu_to_le16(USB_VID_HAUPPAUGE) &&
  adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_STICK)) {
  if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a;
 }
 if (st->is_dib7000pc)
  tun_i2c = state->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
 else
  tun_i2c = dib7000m_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);

 return dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk7700p_mt2060_config,
  if1) == NULL ? -ENODEV : 0;
}

/* DIB7070 generic */
static struct dibx000_agc_config dib7070_agc_config = {
 .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
 /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */

 .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
 .inv_gain = 600,
 .time_stabiliz = 10,
 .alpha_level = 0,
 .thlock = 118,
 .wbd_inv = 0,
 .wbd_ref = 3530,
 .wbd_sel = 1,
 .wbd_alpha = 5,
 .agc1_max = 65535,
 .agc1_min = 0,
 .agc2_max = 65535,
 .agc2_min = 0,
 .agc1_pt1 = 0,
 .agc1_pt2 = 40,
 .agc1_pt3 = 183,
 .agc1_slope1 = 206,
 .agc1_slope2 = 255,
 .agc2_pt1 = 72,
 .agc2_pt2 = 152,
 .agc2_slope1 = 88,
 .agc2_slope2 = 90,
 .alpha_mant = 17,
 .alpha_exp = 27,
 .beta_mant = 23,
 .beta_exp = 51,
 .perform_agc_softsplit = 0,
};

static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
{
 struct dvb_usb_adapter *adap = fe->dvb->priv;
 struct dib0700_adapter_state *state = adap->priv;

 deb_info("reset: %d", onoff);
 return state->dib7000p_ops.set_gpio(fe, 8, 0, !onoff);
}

static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
{
 struct dvb_usb_adapter *adap = fe->dvb->priv;
 struct dib0700_adapter_state *state = adap->priv;

 deb_info("sleep: %d", onoff);
 return state->dib7000p_ops.set_gpio(fe, 9, 0, onoff);
}

static struct dib0070_config dib7070p_dib0070_config[2] = {
 {
  .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
  .reset = dib7070_tuner_reset,
  .sleep = dib7070_tuner_sleep,
  .clock_khz = 12000,
  .clock_pad_drive = 4,
  .charge_pump = 2,
 }, {
  .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
  .reset = dib7070_tuner_reset,
  .sleep = dib7070_tuner_sleep,
  .clock_khz = 12000,
  .charge_pump = 2,
 }
};

static struct dib0070_config dib7770p_dib0070_config = {
  .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
  .reset = dib7070_tuner_reset,
  .sleep = dib7070_tuner_sleep,
  .clock_khz = 12000,
  .clock_pad_drive = 0,
  .flip_chip = 1,
  .charge_pump = 2,
};

static int dib7070_set_param_override(struct dvb_frontend *fe)
{
 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 struct dvb_usb_adapter *adap = fe->dvb->priv;
 struct dib0700_adapter_state *state = adap->priv;

 u16 offset;
 u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
 switch (band) {
  case BAND_VHF: offset = 950; break;
  case BAND_UHF:
  default: offset = 550; break;
 }
 deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
 state->dib7000p_ops.set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
 return state->set_param_save(fe);
}

static int dib7770_set_param_override(struct dvb_frontend *fe)
{
 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 struct dvb_usb_adapter *adap = fe->dvb->priv;
 struct dib0700_adapter_state *state = adap->priv;

 u16 offset;
 u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
 switch (band) {
 case BAND_VHF:
  state->dib7000p_ops.set_gpio(fe, 0, 0, 1);
  offset = 850;
  break;
 case BAND_UHF:
 default:
  state->dib7000p_ops.set_gpio(fe, 0, 0, 0);
  offset = 250;
  break;
 }
 deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
 state->dib7000p_ops.set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
 return state->set_param_save(fe);
}

static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap)
{
 struct dib0700_adapter_state *st = adap->priv;
 struct i2c_adapter *tun_i2c = st->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe,
    DIBX000_I2C_INTERFACE_TUNER, 1);

 if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
         &dib7770p_dib0070_config) == NULL)
  return -ENODEV;

 st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
 adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7770_set_param_override;
 return 0;
}

static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap)
{
 struct dib0700_adapter_state *st = adap->priv;
 struct i2c_adapter *tun_i2c = st->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);

 if (adap->id == 0) {
  if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL)
   return -ENODEV;
 } else {
  if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL)
   return -ENODEV;
 }

 st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
 adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7070_set_param_override;
 return 0;
}

static int stk7700p_pid_filter(struct dvb_usb_adapter *adapter, int index,
  u16 pid, int onoff)
{
 struct dib0700_adapter_state *state = adapter->priv;
 struct dib0700_state *st = adapter->dev->priv;

 if (st->is_dib7000pc)
  return state->dib7000p_ops.pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
 return dib7000m_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
}

static int stk7700p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
{
 struct dib0700_state *st = adapter->dev->priv;
 struct dib0700_adapter_state *state = adapter->priv;
 if (st->is_dib7000pc)
  return state->dib7000p_ops.pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
 return dib7000m_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
}

static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
{
 struct dib0700_adapter_state *state = adapter->priv;
 return state->dib7000p_ops.pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
}

static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
{
 struct dib0700_adapter_state *state = adapter->priv;
 return state->dib7000p_ops.pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
}

static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
 .internal = 60000,
 .sampling = 15000,
 .pll_prediv = 1,
 .pll_ratio = 20,
 .pll_range = 3,
 .pll_reset = 1,
 .pll_bypass = 0,
 .enable_refdiv = 0,
 .bypclk_div = 0,
 .IO_CLK_en_core = 1,
 .ADClkSrc = 1,
 .modulo = 2,
 .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
 .ifreq = (0 << 25) | 0,
 .timf = 20452225,
 .xtal_hz = 12000000,
};

static struct dib7000p_config dib7070p_dib7000p_config = {
 .output_mpeg2_in_188_bytes = 1,

 .agc_config_count = 1,
 .agc = &dib7070_agc_config,
 .bw  = &dib7070_bw_config_12_mhz,
 .tuner_is_baseband = 1,
 .spur_protect = 1,

 .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
 .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
 .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,

 .hostbus_diversity = 1,
};

/* STK7070P */
static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
{
 struct usb_device_descriptor *p = &adap->dev->udev->descriptor;
 struct dib0700_adapter_state *state = adap->priv;

 if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
  return -ENODEV;

 if (p->idVendor  == cpu_to_le16(USB_VID_PINNACLE) &&
     p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E))
  dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
 else
  dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
 msleep(10);
 dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);

 dib0700_ctrl_clock(adap->dev, 72, 1);

 msleep(10);
 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
 msleep(10);
 dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);

 if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
         &dib7070p_dib7000p_config) != 0) {
  err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n",
      __func__);
  dvb_detach(state->dib7000p_ops.set_wbd_ref);
  return -ENODEV;
 }

 adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80,
  &dib7070p_dib7000p_config);
 return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}

/* STK7770P */
static struct dib7000p_config dib7770p_dib7000p_config = {
 .output_mpeg2_in_188_bytes = 1,

 .agc_config_count = 1,
 .agc = &dib7070_agc_config,
 .bw  = &dib7070_bw_config_12_mhz,
 .tuner_is_baseband = 1,
 .spur_protect = 1,

 .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
 .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
 .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,

 .hostbus_diversity = 1,
 .enable_current_mirror = 1,
 .disable_sample_and_hold = 0,
};

static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap)
{
 struct usb_device_descriptor *p = &adap->dev->udev->descriptor;
 struct dib0700_adapter_state *state = adap->priv;

 if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
  return -ENODEV;

 if (p->idVendor  == cpu_to_le16(USB_VID_PINNACLE) &&
     p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E))
  dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
 else
  dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
 msleep(10);
 dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);

 dib0700_ctrl_clock(adap->dev, 72, 1);

 msleep(10);
 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
 msleep(10);
 dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);

 if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
         &dib7770p_dib7000p_config) != 0) {
  err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n",
      __func__);
  dvb_detach(state->dib7000p_ops.set_wbd_ref);
  return -ENODEV;
 }

 adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80,
  &dib7770p_dib7000p_config);
 return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}

/* DIB807x generic */
static struct dibx000_agc_config dib807x_agc_config[2] = {
 {
  BAND_VHF,
  /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
 * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
 * P_agc_inv_pwm2=0,P_agc_inh_dc_rv_est=0,
 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
 * P_agc_write=0 */

  (0 << 15) | (0 << 14) | (7 << 11) | (0 << 10) | (0 << 9) |
   (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) |
   (0 << 0), /* setup*/

  600, /* inv_gain*/
  10,  /* time_stabiliz*/

  0,  /* alpha_level*/
  118,  /* thlock*/

  0,     /* wbd_inv*/
  3530,  /* wbd_ref*/
  1,     /* wbd_sel*/
  5,     /* wbd_alpha*/

  65535,  /* agc1_max*/
  0,  /* agc1_min*/

  65535,  /* agc2_max*/
  0,      /* agc2_min*/

  0,      /* agc1_pt1*/
  40,     /* agc1_pt2*/
  183,    /* agc1_pt3*/
  206,    /* agc1_slope1*/
  255,    /* agc1_slope2*/
  72,     /* agc2_pt1*/
  152,    /* agc2_pt2*/
  88,     /* agc2_slope1*/
  90,     /* agc2_slope2*/

  17,  /* alpha_mant*/
  27,  /* alpha_exp*/
  23,  /* beta_mant*/
  51,  /* beta_exp*/

  0,  /* perform_agc_softsplit*/
 }, {
  BAND_UHF,
  /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
 * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
 * P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
 * P_agc_write=0 */

  (0 << 15) | (0 << 14) | (1 << 11) | (0 << 10) | (0 << 9) |
   (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) |
   (0 << 0), /* setup */

  600, /* inv_gain*/
  10,  /* time_stabiliz*/

  0,  /* alpha_level*/
  118,  /* thlock*/

  0,     /* wbd_inv*/
  3530,  /* wbd_ref*/
  1,     /* wbd_sel*/
  5,     /* wbd_alpha*/

  65535,  /* agc1_max*/
  0,  /* agc1_min*/

  65535,  /* agc2_max*/
  0,      /* agc2_min*/

  0,      /* agc1_pt1*/
  40,     /* agc1_pt2*/
  183,    /* agc1_pt3*/
  206,    /* agc1_slope1*/
  255,    /* agc1_slope2*/
  72,     /* agc2_pt1*/
  152,    /* agc2_pt2*/
  88,     /* agc2_slope1*/
  90,     /* agc2_slope2*/

  17,  /* alpha_mant*/
  27,  /* alpha_exp*/
  23,  /* beta_mant*/
  51,  /* beta_exp*/

  0,  /* perform_agc_softsplit*/
 }
};

static struct dibx000_bandwidth_config dib807x_bw_config_12_mhz = {
 .internal = 60000,
 .sampling = 15000,
 .pll_prediv = 1,
 .pll_ratio = 20,
 .pll_range = 3,
 .pll_reset = 1,
 .pll_bypass = 0,
 .enable_refdiv = 0,
 .bypclk_div = 0,
 .IO_CLK_en_core = 1,
 .ADClkSrc = 1,
 .modulo = 2,
 .sad_cfg = (3 << 14) | (1 << 12) | (599 << 0), /* sad_cfg: refsel, sel, freq_15k*/
 .ifreq = (0 << 25) | 0,    /* ifreq = 0.000000 MHz*/
 .timf = 18179755,
 .xtal_hz = 12000000,
};

static struct dib8000_config dib807x_dib8000_config[2] = {
 {
  .output_mpeg2_in_188_bytes = 1,

  .agc_config_count = 2,
  .agc = dib807x_agc_config,
  .pll = &dib807x_bw_config_12_mhz,
  .tuner_is_baseband = 1,

  .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
  .gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
  .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,

  .hostbus_diversity = 1,
  .div_cfg = 1,
  .agc_control = &dib0070_ctrl_agc_filter,
  .output_mode = OUTMODE_MPEG2_FIFO,
  .drives = 0x2d98,
 }, {
  .output_mpeg2_in_188_bytes = 1,

  .agc_config_count = 2,
  .agc = dib807x_agc_config,
  .pll = &dib807x_bw_config_12_mhz,
  .tuner_is_baseband = 1,

  .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
  .gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
  .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,

  .hostbus_diversity = 1,
  .agc_control = &dib0070_ctrl_agc_filter,
  .output_mode = OUTMODE_MPEG2_FIFO,
  .drives = 0x2d98,
 }
};

static int dib80xx_tuner_reset(struct dvb_frontend *fe, int onoff)
{
 struct dvb_usb_adapter *adap = fe->dvb->priv;
 struct dib0700_adapter_state *state = adap->priv;

 return state->dib8000_ops.set_gpio(fe, 5, 0, !onoff);
}

static int dib80xx_tuner_sleep(struct dvb_frontend *fe, int onoff)
{
 struct dvb_usb_adapter *adap = fe->dvb->priv;
 struct dib0700_adapter_state *state = adap->priv;

 return state->dib8000_ops.set_gpio(fe, 0, 0, onoff);
}

static const struct dib0070_wbd_gain_cfg dib8070_wbd_gain_cfg[] = {
    { 240,      7},
    { 0xffff,   6},
};

static struct dib0070_config dib807x_dib0070_config[2] = {
 {
  .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
  .reset = dib80xx_tuner_reset,
  .sleep = dib80xx_tuner_sleep,
  .clock_khz = 12000,
  .clock_pad_drive = 4,
  .vga_filter = 1,
  .force_crystal_mode = 1,
  .enable_third_order_filter = 1,
  .charge_pump = 0,
  .wbd_gain = dib8070_wbd_gain_cfg,
  .osc_buffer_state = 0,
  .freq_offset_khz_uhf = -100,
  .freq_offset_khz_vhf = -100,
 }, {
  .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
  .reset = dib80xx_tuner_reset,
  .sleep = dib80xx_tuner_sleep,
  .clock_khz = 12000,
  .clock_pad_drive = 2,
  .vga_filter = 1,
  .force_crystal_mode = 1,
  .enable_third_order_filter = 1,
  .charge_pump = 0,
  .wbd_gain = dib8070_wbd_gain_cfg,
  .osc_buffer_state = 0,
  .freq_offset_khz_uhf = -25,
  .freq_offset_khz_vhf = -25,
 }
};

static int dib807x_set_param_override(struct dvb_frontend *fe)
{
 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 struct dvb_usb_adapter *adap = fe->dvb->priv;
 struct dib0700_adapter_state *state = adap->priv;

 u16 offset = dib0070_wbd_offset(fe);
 u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
 switch (band) {
 case BAND_VHF:
  offset += 750;
  break;
 case BAND_UHF:  /* fall-thru wanted */
 default:
  offset += 250; break;
 }
 deb_info("WBD for DiB8000: %d\n", offset);
 state->dib8000_ops.set_wbd_ref(fe, offset);

 return state->set_param_save(fe);
}

static int dib807x_tuner_attach(struct dvb_usb_adapter *adap)
{
 struct dib0700_adapter_state *st = adap->priv;
 struct i2c_adapter *tun_i2c = st->dib8000_ops.get_i2c_master(adap->fe_adap[0].fe,
   DIBX000_I2C_INTERFACE_TUNER, 1);

 if (adap->id == 0) {
  if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
    &dib807x_dib0070_config[0]) == NULL)
   return -ENODEV;
 } else {
  if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
    &dib807x_dib0070_config[1]) == NULL)
   return -ENODEV;
 }

 st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
 adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib807x_set_param_override;
 return 0;
}

static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index,
 u16 pid, int onoff)
{
 struct dib0700_adapter_state *state = adapter->priv;

 return state->dib8000_ops.pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
}

static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter,
  int onoff)
{
 struct dib0700_adapter_state *state = adapter->priv;

 return state->dib8000_ops.pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
}

/* STK807x */
static int stk807x_frontend_attach(struct dvb_usb_adapter *adap)
{
 struct dib0700_adapter_state *state = adap->priv;

 if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
  return -ENODEV;

 dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
 msleep(10);
 dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);

 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);

 dib0700_ctrl_clock(adap->dev, 72, 1);

 msleep(10);
 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
 msleep(10);
 dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);

 state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
    0x80, 0);

 adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x80,
         &dib807x_dib8000_config[0]);

 return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
}

/* STK807xPVR */
static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap)
{
 struct dib0700_adapter_state *state = adap->priv;

 if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
  return -ENODEV;

 dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
 msleep(30);
 dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
 msleep(500);
 dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);

 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);

 dib0700_ctrl_clock(adap->dev, 72, 1);

 msleep(10);
 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
 msleep(10);
 dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);

 /* initialize IC 0 */
 state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80, 0);

 adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x80,
         &dib807x_dib8000_config[0]);

 return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}

static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
{
 struct dib0700_adapter_state *state = adap->priv;

 if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
  return -ENODEV;

 /* initialize IC 1 */
 state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82, 0);

 adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x82,
         &dib807x_dib8000_config[1]);

 return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}

/* STK8096GP */
static struct dibx000_agc_config dib8090_agc_config[2] = {
 {
 .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
 /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */

 .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
 | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),

 .inv_gain = 787,
 .time_stabiliz = 10,

 .alpha_level = 0,
 .thlock = 118,

 .wbd_inv = 0,
 .wbd_ref = 3530,
 .wbd_sel = 1,
 .wbd_alpha = 5,

 .agc1_max = 65535,
 .agc1_min = 0,

 .agc2_max = 65535,
 .agc2_min = 0,

 .agc1_pt1 = 0,
 .agc1_pt2 = 32,
 .agc1_pt3 = 114,
 .agc1_slope1 = 143,
 .agc1_slope2 = 144,
 .agc2_pt1 = 114,
 .agc2_pt2 = 227,
 .agc2_slope1 = 116,
 .agc2_slope2 = 117,

 .alpha_mant = 28,
 .alpha_exp = 26,
 .beta_mant = 31,
 .beta_exp = 51,

 .perform_agc_softsplit = 0,
 },
 {
 .band_caps = BAND_CBAND,
 /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */

 .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
 | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),

 .inv_gain = 787,
 .time_stabiliz = 10,

 .alpha_level = 0,
 .thlock = 118,

 .wbd_inv = 0,
 .wbd_ref = 3530,
 .wbd_sel = 1,
 .wbd_alpha = 5,

 .agc1_max = 0,
 .agc1_min = 0,

 .agc2_max = 65535,
 .agc2_min = 0,

 .agc1_pt1 = 0,
 .agc1_pt2 = 32,
 .agc1_pt3 = 114,
 .agc1_slope1 = 143,
 .agc1_slope2 = 144,
 .agc2_pt1 = 114,
 .agc2_pt2 = 227,
 .agc2_slope1 = 116,
 .agc2_slope2 = 117,

 .alpha_mant = 28,
 .alpha_exp = 26,
 .beta_mant = 31,
 .beta_exp = 51,

 .perform_agc_softsplit = 0,
 }
};

static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = {
 .internal = 54000,
 .sampling = 13500,

 .pll_prediv = 1,
 .pll_ratio = 18,
 .pll_range = 3,
 .pll_reset = 1,
 .pll_bypass = 0,

 .enable_refdiv = 0,
 .bypclk_div = 0,
 .IO_CLK_en_core = 1,
 .ADClkSrc = 1,
 .modulo = 2,

 .sad_cfg = (3 << 14) | (1 << 12) | (599 << 0),

 .ifreq = (0 << 25) | 0,
 .timf = 20199727,

 .xtal_hz = 12000000,
};

static int dib8090_get_adc_power(struct dvb_frontend *fe)
{
 struct dvb_usb_adapter *adap = fe->dvb->priv;
 struct dib0700_adapter_state *state = adap->priv;

 return state->dib8000_ops.get_adc_power(fe, 1);
}

static void dib8090_agc_control(struct dvb_frontend *fe, u8 restart)
{
 deb_info("AGC control callback: %i\n", restart);
 dib0090_dcc_freq(fe, restart);

 if (restart == 0) /* before AGC startup */
  dib0090_set_dc_servo(fe, 1);
}

static struct dib8000_config dib809x_dib8000_config[2] = {
 {
 .output_mpeg2_in_188_bytes = 1,

 .agc_config_count = 2,
 .agc = dib8090_agc_config,
 .agc_control = dib8090_agc_control,
 .pll = &dib8090_pll_config_12mhz,
 .tuner_is_baseband = 1,

 .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
 .gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
 .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,

 .hostbus_diversity = 1,
 .div_cfg = 0x31,
 .output_mode = OUTMODE_MPEG2_FIFO,
 .drives = 0x2d98,
 .diversity_delay = 48,
 .refclksel = 3,
 }, {
 .output_mpeg2_in_188_bytes = 1,

 .agc_config_count = 2,
 .agc = dib8090_agc_config,
 .agc_control = dib8090_agc_control,
 .pll = &dib8090_pll_config_12mhz,
 .tuner_is_baseband = 1,

 .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
 .gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
 .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,

 .hostbus_diversity = 1,
 .div_cfg = 0x31,
 .output_mode = OUTMODE_DIVERSITY,
 .drives = 0x2d08,
 .diversity_delay = 1,
 .refclksel = 3,
 }
};

static struct dib0090_wbd_slope dib8090_wbd_table[] = {
 /* max freq ; cold slope ; cold offset ; warm slope ; warm offset ; wbd gain */
 { 120,     0, 500,  0,   500, 4 }, /* CBAND */
 { 170,     0, 450,  0,   450, 4 }, /* CBAND */
 { 380,    48, 373, 28,   259, 6 }, /* VHF */
 { 860,    34, 700, 36,   616, 6 }, /* high UHF */
 { 0xFFFF, 34, 700, 36,   616, 6 }, /* default */
};

static struct dib0090_config dib809x_dib0090_config = {
 .io.pll_bypass = 1,
 .io.pll_range = 1,
 .io.pll_prediv = 1,
 .io.pll_loopdiv = 20,
 .io.adc_clock_ratio = 8,
 .io.pll_int_loop_filt = 0,
 .io.clock_khz = 12000,
 .reset = dib80xx_tuner_reset,
 .sleep = dib80xx_tuner_sleep,
 .clkouttobamse = 1,
 .analog_output = 1,
 .i2c_address = DEFAULT_DIB0090_I2C_ADDRESS,
 .use_pwm_agc = 1,
 .clkoutdrive = 1,
 .get_adc_power = dib8090_get_adc_power,
 .freq_offset_khz_uhf = -63,
 .freq_offset_khz_vhf = -143,
 .wbd = dib8090_wbd_table,
 .fref_clock_ratio = 6,
};

static u8 dib8090_compute_pll_parameters(struct dvb_frontend *fe)
{
 u8 optimal_pll_ratio = 20;
 u32 freq_adc, ratio, rest, max = 0;
 u8 pll_ratio;

 for (pll_ratio = 17; pll_ratio <= 20; pll_ratio++) {
  freq_adc = 12 * pll_ratio * (1 << 8) / 16;
  ratio = ((fe->dtv_property_cache.frequency / 1000) * (1 << 8) / 1000) / freq_adc;
  rest = ((fe->dtv_property_cache.frequency / 1000) * (1 << 8) / 1000) - ratio * freq_adc;

  if (rest > freq_adc / 2)
   rest = freq_adc - rest;
  deb_info("PLL ratio=%i rest=%i\n", pll_ratio, rest);
  if ((rest > max) && (rest > 717)) {
   optimal_pll_ratio = pll_ratio;
   max = rest;
  }
 }
 deb_info("optimal PLL ratio=%i\n", optimal_pll_ratio);

 return optimal_pll_ratio;
}

static int dib8096_set_param_override(struct dvb_frontend *fe)
{
 struct dvb_usb_adapter *adap = fe->dvb->priv;
 struct dib0700_adapter_state *state = adap->priv;
 u8 pll_ratio, band = BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000);
 u16 target, ltgain, rf_gain_limit;
 u32 timf;
 int ret = 0;
 enum frontend_tune_state tune_state = CT_SHUTDOWN;

 switch (band) {
 default:
  deb_info("Warning : Rf frequency (%iHz) is not in the supported range, using VHF switch ", fe->dtv_property_cache.frequency);
  fallthrough;
 case BAND_VHF:
  state->dib8000_ops.set_gpio(fe, 3, 0, 1);
  break;
 case BAND_UHF:
  state->dib8000_ops.set_gpio(fe, 3, 0, 0);
  break;
 }

 ret = state->set_param_save(fe);
 if (ret < 0)
  return ret;

 if (fe->dtv_property_cache.bandwidth_hz != 6000000) {
  deb_info("only 6MHz bandwidth is supported\n");
  return -EINVAL;
 }

 /* Update PLL if needed ratio */
 state->dib8000_ops.update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, 0);

 /* Get optimize PLL ratio to remove spurious */
 pll_ratio = dib8090_compute_pll_parameters(fe);
 if (pll_ratio == 17)
  timf = 21387946;
 else if (pll_ratio == 18)
  timf = 20199727;
 else if (pll_ratio == 19)
  timf = 19136583;
 else
  timf = 18179756;

 /* Update ratio */
 state->dib8000_ops.update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, pll_ratio);

 state->dib8000_ops.ctrl_timf(fe, DEMOD_TIMF_SET, timf);

 if (band != BAND_CBAND) {
  /* dib0090_get_wbd_target is returning any possible temperature compensated wbd-target */
  target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2;
  state->dib8000_ops.set_wbd_ref(fe, target);
 }

 if (band == BAND_CBAND) {
  deb_info("tuning in CBAND - soft-AGC startup\n");
  dib0090_set_tune_state(fe, CT_AGC_START);

  do {
   ret = dib0090_gain_control(fe);
   msleep(ret);
   tune_state = dib0090_get_tune_state(fe);
   if (tune_state == CT_AGC_STEP_0)
    state->dib8000_ops.set_gpio(fe, 6, 0, 1);
   else if (tune_state == CT_AGC_STEP_1) {
    dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain);
    if (rf_gain_limit < 2000) /* activate the external attenuator in case of very high input power */
     state->dib8000_ops.set_gpio(fe, 6, 0, 0);
   }
  } while (tune_state < CT_AGC_STOP);

  deb_info("switching to PWM AGC\n");
  dib0090_pwm_gain_reset(fe);
  state->dib8000_ops.pwm_agc_reset(fe);
  state->dib8000_ops.set_tune_state(fe, CT_DEMOD_START);
 } else {
  /* for everything else than CBAND we are using standard AGC */
  deb_info("not tuning in CBAND - standard AGC startup\n");
  dib0090_pwm_gain_reset(fe);
 }

 return 0;
}

static int dib809x_tuner_attach(struct dvb_usb_adapter *adap)
{
 struct dib0700_adapter_state *st = adap->priv;
 struct i2c_adapter *tun_i2c = st->dib8000_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);

 /* FIXME: if adap->id != 0, check if it is fe_adap[1] */
 if (!dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config))
  return -ENODEV;

 st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
 adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override;
 return 0;
}

static int stk809x_frontend_attach(struct dvb_usb_adapter *adap)
{
 struct dib0700_adapter_state *state = adap->priv;

 if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
  return -ENODEV;

 dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
 msleep(10);
 dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);

 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);

 dib0700_ctrl_clock(adap->dev, 72, 1);

 msleep(10);
 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
 msleep(10);
 dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);

 state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80, 0);

 adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);

 return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
}

static int stk809x_frontend1_attach(struct dvb_usb_adapter *adap)
{
 struct dib0700_adapter_state *state = adap->priv;

 if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
  return -ENODEV;

 state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x82, 0);

 adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]);

 return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
}

static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap)
{
 struct dib0700_adapter_state *st = adap->priv;
 struct i2c_adapter *tun_i2c;
 struct dvb_frontend *fe_slave  = st->dib8000_ops.get_slave_frontend(adap->fe_adap[0].fe, 1);

 if (fe_slave) {
  tun_i2c = st->dib8000_ops.get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1);
  if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL)
   return -ENODEV;
  fe_slave->dvb = adap->fe_adap[0].fe->dvb;
  fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override;
 }
 tun_i2c = st->dib8000_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
 if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL)
  return -ENODEV;

 st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
 adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override;

 return 0;
}

static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap)
{
 struct dvb_frontend *fe_slave;
 struct dib0700_adapter_state *state = adap->priv;

 if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
  return -ENODEV;

 dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
 msleep(20);
 dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
 msleep(1000);
 dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);

 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);

 dib0700_ctrl_clock(adap->dev, 72, 1);

 msleep(20);
 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
 msleep(20);
 dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);

 state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80, 0);

 adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
 if (adap->fe_adap[0].fe == NULL)
  return -ENODEV;

 /* Needed to increment refcount */
 if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
  return -ENODEV;

 fe_slave = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]);
 state->dib8000_ops.set_slave_frontend(adap->fe_adap[0].fe, fe_slave);

 return fe_slave == NULL ?  -ENODEV : 0;
}

/* TFE8096P */
static struct dibx000_agc_config dib8096p_agc_config[2] = {
 {
  .band_caps  = BAND_UHF,
  /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
   P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
   P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
   P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
   P_agc_write=0 */

  .setup   = (0 << 15) | (0 << 14) | (5 << 11)
   | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5)
   | (0 << 4) | (5 << 1) | (0 << 0),

  .inv_gain  = 684,
  .time_stabiliz = 10,

  .alpha_level = 0,
  .thlock   = 118,

  .wbd_inv  = 0,
  .wbd_ref  = 1200,
  .wbd_sel  = 3,
  .wbd_alpha  = 5,

  .agc1_max  = 65535,
  .agc1_min  = 0,

  .agc2_max  = 32767,
  .agc2_min  = 0,

  .agc1_pt1  = 0,
  .agc1_pt2  = 0,
  .agc1_pt3  = 105,
  .agc1_slope1 = 0,
  .agc1_slope2 = 156,
  .agc2_pt1  = 105,
  .agc2_pt2  = 255,
  .agc2_slope1 = 54,
  .agc2_slope2 = 0,

  .alpha_mant  = 28,
  .alpha_exp  = 26,
  .beta_mant  = 31,
  .beta_exp  = 51,

  .perform_agc_softsplit = 0,
 } , {
  .band_caps  = BAND_FM | BAND_VHF | BAND_CBAND,
  /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
   P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
   P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
   P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
   P_agc_write=0 */

  .setup   = (0 << 15) | (0 << 14) | (5 << 11)
   | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5)
   | (0 << 4) | (5 << 1) | (0 << 0),

  .inv_gain  = 732,
  .time_stabiliz  = 10,

  .alpha_level = 0,
  .thlock   = 118,

  .wbd_inv  = 0,
  .wbd_ref  = 1200,
  .wbd_sel  = 3,
  .wbd_alpha  = 5,

  .agc1_max  = 65535,
  .agc1_min  = 0,

  .agc2_max  = 32767,
  .agc2_min  = 0,

  .agc1_pt1  = 0,
  .agc1_pt2  = 0,
  .agc1_pt3  = 98,
  .agc1_slope1 = 0,
  .agc1_slope2 = 167,
  .agc2_pt1  = 98,
  .agc2_pt2  = 255,
  .agc2_slope1 = 52,
  .agc2_slope2 = 0,

  .alpha_mant  = 28,
  .alpha_exp  = 26,
  .beta_mant  = 31,
  .beta_exp  = 51,

  .perform_agc_softsplit = 0,
 }
};

static struct dibx000_bandwidth_config dib8096p_clock_config_12_mhz = {
 .internal = 108000,
 .sampling = 13500,
 .pll_prediv = 1,
 .pll_ratio = 9,
 .pll_range = 1,
 .pll_reset = 0,
 .pll_bypass = 0,
 .enable_refdiv = 0,
 .bypclk_div = 0,
 .IO_CLK_en_core = 0,
 .ADClkSrc = 0,
 .modulo = 2,
 .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
 .ifreq = (0 << 25) | 0,
 .timf = 20199729,
 .xtal_hz = 12000000,
};

static struct dib8000_config tfe8096p_dib8000_config = {
 .output_mpeg2_in_188_bytes = 1,
 .hostbus_diversity   = 1,
 .update_lna     = NULL,

 .agc_config_count   = 2,
 .agc      = dib8096p_agc_config,
 .pll      = &dib8096p_clock_config_12_mhz,

 .gpio_dir     = DIB8000_GPIO_DEFAULT_DIRECTIONS,
 .gpio_val     = DIB8000_GPIO_DEFAULT_VALUES,
 .gpio_pwm_pos    = DIB8000_GPIO_DEFAULT_PWM_POS,

 .agc_control    = NULL,
 .diversity_delay   = 48,
 .output_mode    = OUTMODE_MPEG2_FIFO,
 .enMpegOutput    = 1,
};

static struct dib0090_wbd_slope dib8096p_wbd_table[] = {
 { 380, 81, 850, 64, 540, 4},
 { 860, 51, 866, 21, 375, 4},
 {1700, 0, 250, 0, 100, 6},
 {2600, 0, 250, 0, 100, 6},
 { 0xFFFF, 0, 0, 0, 0, 0},
};

static struct dib0090_config tfe8096p_dib0090_config = {
 .io.clock_khz   = 12000,
 .io.pll_bypass   = 0,
 .io.pll_range   = 0,
 .io.pll_prediv   = 3,
 .io.pll_loopdiv   = 6,
 .io.adc_clock_ratio  = 0,
 .io.pll_int_loop_filt = 0,

 .freq_offset_khz_uhf = -143,
 .freq_offset_khz_vhf = -143,

 .get_adc_power   = dib8090_get_adc_power,

 .clkouttobamse   = 1,
 .analog_output   = 0,

 .wbd_vhf_offset   = 0,
 .wbd_cband_offset  = 0,
 .use_pwm_agc   = 1,
 .clkoutdrive   = 0,

 .fref_clock_ratio  = 1,

 .ls_cfg_pad_drv   = 0,
 .data_tx_drv   = 0,
 .low_if     = NULL,
 .in_soc     = 1,
 .force_cband_input  = 0,
};

struct dibx090p_best_adc {
 u32 timf;
 u32 pll_loopdiv;
 u32 pll_prediv;
};

static int dib8096p_get_best_sampling(struct dvb_frontend *fe, struct dibx090p_best_adc *adc)
{
 u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1;
 u16 xtal = 12000;
 u16 fcp_min = 1900;  /* PLL, Minimum Frequency of phase comparator (KHz) */
 u16 fcp_max = 20000; /* PLL, Maximum Frequency of phase comparator (KHz) */
 u32 fmem_max = 140000; /* 140MHz max SDRAM freq */
 u32 fdem_min = 66000;
 u32 fcp = 0, fs = 0, fdem = 0, fmem = 0;
 u32 harmonic_id = 0;

 adc->timf = 0;
 adc->pll_loopdiv = loopdiv;
 adc->pll_prediv = prediv;

 deb_info("bandwidth = %d", fe->dtv_property_cache.bandwidth_hz);

 /* Find Min and Max prediv */
 while ((xtal / max_prediv) >= fcp_min)
  max_prediv++;

 max_prediv--;
 min_prediv = max_prediv;
 while ((xtal / min_prediv) <= fcp_max) {
  min_prediv--;
  if (min_prediv == 1)
   break;
 }
 deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv);

 min_prediv = 1;

 for (prediv = min_prediv; prediv < max_prediv; prediv++) {
  fcp = xtal / prediv;
  if (fcp > fcp_min && fcp < fcp_max) {
   for (loopdiv = 1; loopdiv < 64; loopdiv++) {
    fmem = ((xtal/prediv) * loopdiv);
    fdem = fmem / 2;
    fs   = fdem / 4;

    /* test min/max system restrictions */
    if ((fdem >= fdem_min) && (fmem <= fmem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz / 1000)) {
     spur = 0;
     /* test fs harmonics positions */
     for (harmonic_id = (fe->dtv_property_cache.frequency / (1000 * fs));  harmonic_id <= ((fe->dtv_property_cache.frequency / (1000 * fs)) + 1); harmonic_id++) {
      if (((fs * harmonic_id) >= (fe->dtv_property_cache.frequency / 1000 - (fe->dtv_property_cache.bandwidth_hz / 2000))) &&  ((fs * harmonic_id) <= (fe->dtv_property_cache.frequency / 1000 + (fe->dtv_property_cache.bandwidth_hz / 2000)))) {
       spur = 1;
       break;
      }
     }

     if (!spur) {
      adc->pll_loopdiv = loopdiv;
      adc->pll_prediv = prediv;
      adc->timf = (4260880253U / fdem) * (1 << 8);
      adc->timf += ((4260880253U % fdem) << 8) / fdem;

      deb_info("RF %6d; BW %6d; Xtal %6d; Fmem %6d; Fdem %6d; Fs %6d; Prediv %2d; Loopdiv %2d; Timf %8d;", fe->dtv_property_cache.frequency, fe->dtv_property_cache.bandwidth_hz, xtal, fmem, fdem, fs, prediv, loopdiv, adc->timf);
      break;
     }
    }
   }
  }
  if (!spur)
   break;
 }

 if (adc->pll_loopdiv == 0 && adc->pll_prediv == 0)
  return -EINVAL;
 return 0;
}

static int dib8096p_agc_startup(struct dvb_frontend *fe)
{
 struct dvb_usb_adapter *adap = fe->dvb->priv;
 struct dib0700_adapter_state *state = adap->priv;
 struct dibx000_bandwidth_config pll;
 struct dibx090p_best_adc adc;
 u16 target;
 int ret;

 ret = state->set_param_save(fe);
 if (ret < 0)
  return ret;
 memset(&pll, 0, sizeof(struct dibx000_bandwidth_config));

 dib0090_pwm_gain_reset(fe);
 /* dib0090_get_wbd_target is returning any possible
   temperature compensated wbd-target */

 target = (dib0090_get_wbd_target(fe) * 8  + 1) / 2;
 state->dib8000_ops.set_wbd_ref(fe, target);

 if (dib8096p_get_best_sampling(fe, &adc) == 0) {
  pll.pll_ratio  = adc.pll_loopdiv;
  pll.pll_prediv = adc.pll_prediv;

  dib0700_set_i2c_speed(adap->dev, 200);
  state->dib8000_ops.update_pll(fe, &pll, fe->dtv_property_cache.bandwidth_hz / 1000, 0);
  state->dib8000_ops.ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf);
  dib0700_set_i2c_speed(adap->dev, 1000);
 }
 return 0;
}

static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap)
{
 struct dib0700_state *st = adap->dev->priv;
 u32 fw_version;
 struct dib0700_adapter_state *state = adap->priv;

 if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
  return -ENODEV;

 dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL);
 if (fw_version >= 0x10200)
  st->fw_use_new_i2c_api = 1;

 dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
 msleep(20);
 dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);

 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);

 dib0700_ctrl_clock(adap->dev, 72, 1);

 msleep(20);
 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
 msleep(20);
 dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);

 state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80, 1);

 adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap,
          0x80, &tfe8096p_dib8000_config);

 return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
}

static int tfe8096p_tuner_attach(struct dvb_usb_adapter *adap)
{
 struct dib0700_adapter_state *st = adap->priv;
 struct i2c_adapter *tun_i2c = st->dib8000_ops.get_i2c_tuner(adap->fe_adap[0].fe);

 tfe8096p_dib0090_config.reset = st->dib8000_ops.tuner_sleep;
 tfe8096p_dib0090_config.sleep = st->dib8000_ops.tuner_sleep;
 tfe8096p_dib0090_config.wbd = dib8096p_wbd_table;

 if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
    &tfe8096p_dib0090_config) == NULL)
  return -ENODEV;

 st->dib8000_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);

 st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
 adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096p_agc_startup;
 return 0;
}

/* STK9090M */
static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
{
 return dib9000_fw_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
}

static int dib90x0_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
{
 return dib9000_fw_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
}

static int dib90x0_tuner_reset(struct dvb_frontend *fe, int onoff)
{
 return dib9000_set_gpio(fe, 5, 0, !onoff);
}

static int dib90x0_tuner_sleep(struct dvb_frontend *fe, int onoff)
{
 return dib9000_set_gpio(fe, 0, 0, onoff);
}

static int dib01x0_pmu_update(struct i2c_adapter *i2c, u16 *data, u8 len)
{
 u8 wb[4] = { 0xc >> 8, 0xc & 0xff, 0, 0 };
 u8 rb[2];
 struct i2c_msg msg[2] = {
  {.addr = 0x1e >> 1, .flags = 0, .buf = wb, .len = 2},
  {.addr = 0x1e >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2},
 };
 u8 index_data;

 dibx000_i2c_set_speed(i2c, 250);

 if (i2c_transfer(i2c, msg, 2) != 2)
  return -EIO;

 switch (rb[0] << 8 | rb[1]) {
 case 0:
   deb_info("Found DiB0170 rev1: This version of DiB0170 is not supported any longer.\n");
   return -EIO;
 case 1:
   deb_info("Found DiB0170 rev2");
   break;
 case 2:
   deb_info("Found DiB0190 rev2");
   break;
 default:
   deb_info("DiB01x0 not found");
   return -EIO;
 }

 for (index_data = 0; index_data < len; index_data += 2) {
  wb[2] = (data[index_data + 1] >> 8) & 0xff;
  wb[3] = (data[index_data + 1]) & 0xff;

  if (data[index_data] == 0) {
   wb[0] = (data[index_data] >> 8) & 0xff;
   wb[1] = (data[index_data]) & 0xff;
   msg[0].len = 2;
   if (i2c_transfer(i2c, msg, 2) != 2)
    return -EIO;
   wb[2] |= rb[0];
   wb[3] |= rb[1] & ~(3 << 4);
  }

  wb[0] = (data[index_data] >> 8)&0xff;
  wb[1] = (data[index_data])&0xff;
  msg[0].len = 4;
  if (i2c_transfer(i2c, &msg[0], 1) != 1)
   return -EIO;
 }
 return 0;
}

static struct dib9000_config stk9090m_config = {
 .output_mpeg2_in_188_bytes = 1,
 .output_mode = OUTMODE_MPEG2_FIFO,
 .vcxo_timer = 279620,
 .timing_frequency = 20452225,
 .demod_clock_khz = 60000,
 .xtal_clock_khz = 30000,
 .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0),
 .subband = {
  2,
  {
   { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0008 } }, /* GPIO 3 to 1 for VHF */
   { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0000 } }, /* GPIO 3 to 0 for UHF */
   { 0 },
  },
 },
 .gpio_function = {
  { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 },
  { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 },
 },
};

static struct dib9000_config nim9090md_config[2] = {
 {
  .output_mpeg2_in_188_bytes = 1,
  .output_mode = OUTMODE_MPEG2_FIFO,
  .vcxo_timer = 279620,
  .timing_frequency = 20452225,
  .demod_clock_khz = 60000,
  .xtal_clock_khz = 30000,
  .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0),
 }, {
  .output_mpeg2_in_188_bytes = 1,
  .output_mode = OUTMODE_DIVERSITY,
  .vcxo_timer = 279620,
  .timing_frequency = 20452225,
  .demod_clock_khz = 60000,
  .xtal_clock_khz = 30000,
  .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0),
  .subband = {
   2,
   {
    { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0006 } }, /* GPIO 1 and 2 to 1 for VHF */
    { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0000 } }, /* GPIO 1 and 2 to 0 for UHF */
    { 0 },
   },
  },
  .gpio_function = {
   { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 },
   { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 },
  },
 }
};

static struct dib0090_config dib9090_dib0090_config = {
 .io.pll_bypass = 0,
 .io.pll_range = 1,
 .io.pll_prediv = 1,
 .io.pll_loopdiv = 8,
 .io.adc_clock_ratio = 8,
 .io.pll_int_loop_filt = 0,
 .io.clock_khz = 30000,
 .reset = dib90x0_tuner_reset,
 .sleep = dib90x0_tuner_sleep,
 .clkouttobamse = 0,
 .analog_output = 0,
 .use_pwm_agc = 0,
 .clkoutdrive = 0,
 .freq_offset_khz_uhf = 0,
 .freq_offset_khz_vhf = 0,
};

static struct dib0090_config nim9090md_dib0090_config[2] = {
 {
  .io.pll_bypass = 0,
  .io.pll_range = 1,
  .io.pll_prediv = 1,
  .io.pll_loopdiv = 8,
  .io.adc_clock_ratio = 8,
  .io.pll_int_loop_filt = 0,
  .io.clock_khz = 30000,
  .reset = dib90x0_tuner_reset,
  .sleep = dib90x0_tuner_sleep,
  .clkouttobamse = 1,
  .analog_output = 0,
  .use_pwm_agc = 0,
  .clkoutdrive = 0,
  .freq_offset_khz_uhf = 0,
  .freq_offset_khz_vhf = 0,
 }, {
  .io.pll_bypass = 0,
  .io.pll_range = 1,
  .io.pll_prediv = 1,
  .io.pll_loopdiv = 8,
  .io.adc_clock_ratio = 8,
  .io.pll_int_loop_filt = 0,
  .io.clock_khz = 30000,
  .reset = dib90x0_tuner_reset,
  .sleep = dib90x0_tuner_sleep,
  .clkouttobamse = 0,
  .analog_output = 0,
  .use_pwm_agc = 0,
  .clkoutdrive = 0,
  .freq_offset_khz_uhf = 0,
  .freq_offset_khz_vhf = 0,
 }
};


static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap)
{
 struct dib0700_adapter_state *state = adap->priv;
 struct dib0700_state *st = adap->dev->priv;
 u32 fw_version;

 /* Make use of the new i2c functions from FW 1.20 */
 dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL);
 if (fw_version >= 0x10200)
  st->fw_use_new_i2c_api = 1;
 dib0700_set_i2c_speed(adap->dev, 340);

 dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
 msleep(20);
 dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
 dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=98 G=96

¤ Dauer der Verarbeitung: 0.9 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.