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

Quelle  drxk_hard.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * drxk_hard: DRX-K DVB-C/T demodulator driver
 *
 * Copyright (C) 2010-2011 Digital Devices GmbH
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/hardirq.h>
#include <asm/div64.h>

#include <media/dvb_frontend.h>
#include "drxk.h"
#include "drxk_hard.h"
#include <linux/int_log.h>

static int power_down_dvbt(struct drxk_state *state, bool set_power_mode);
static int power_down_qam(struct drxk_state *state);
static int set_dvbt_standard(struct drxk_state *state,
      enum operation_mode o_mode);
static int set_qam_standard(struct drxk_state *state,
     enum operation_mode o_mode);
static int set_qam(struct drxk_state *state, u16 intermediate_freqk_hz,
    s32 tuner_freq_offset);
static int set_dvbt_standard(struct drxk_state *state,
      enum operation_mode o_mode);
static int dvbt_start(struct drxk_state *state);
static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz,
     s32 tuner_freq_offset);
static int get_qam_lock_status(struct drxk_state *state, u32 *p_lock_status);
static int get_dvbt_lock_status(struct drxk_state *state, u32 *p_lock_status);
static int switch_antenna_to_qam(struct drxk_state *state);
static int switch_antenna_to_dvbt(struct drxk_state *state);

static bool is_dvbt(struct drxk_state *state)
{
 return state->m_operation_mode == OM_DVBT;
}

static bool is_qam(struct drxk_state *state)
{
 return state->m_operation_mode == OM_QAM_ITU_A ||
     state->m_operation_mode == OM_QAM_ITU_B ||
     state->m_operation_mode == OM_QAM_ITU_C;
}

#define NOA1ROM 0

#define DRXDAP_FASI_SHORT_FORMAT(addr) (((addr) & 0xFC30FF80) == 0)
#define DRXDAP_FASI_LONG_FORMAT(addr)  (((addr) & 0xFC30FF80) != 0)

#define DEFAULT_MER_83  165
#define DEFAULT_MER_93  250

#ifndef DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH
#define DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH (0x02)
#endif

#ifndef DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH
#define DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH (0x03)
#endif

#define DEFAULT_DRXK_MPEG_LOCK_TIMEOUT 700
#define DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT 500

#ifndef DRXK_KI_RAGC_ATV
#define DRXK_KI_RAGC_ATV   4
#endif
#ifndef DRXK_KI_IAGC_ATV
#define DRXK_KI_IAGC_ATV   6
#endif
#ifndef DRXK_KI_DAGC_ATV
#define DRXK_KI_DAGC_ATV   7
#endif

#ifndef DRXK_KI_RAGC_QAM
#define DRXK_KI_RAGC_QAM   3
#endif
#ifndef DRXK_KI_IAGC_QAM
#define DRXK_KI_IAGC_QAM   4
#endif
#ifndef DRXK_KI_DAGC_QAM
#define DRXK_KI_DAGC_QAM   7
#endif
#ifndef DRXK_KI_RAGC_DVBT
#define DRXK_KI_RAGC_DVBT  (IsA1WithPatchCode(state) ? 3 : 2)
#endif
#ifndef DRXK_KI_IAGC_DVBT
#define DRXK_KI_IAGC_DVBT  (IsA1WithPatchCode(state) ? 4 : 2)
#endif
#ifndef DRXK_KI_DAGC_DVBT
#define DRXK_KI_DAGC_DVBT  (IsA1WithPatchCode(state) ? 10 : 7)
#endif

#ifndef DRXK_AGC_DAC_OFFSET
#define DRXK_AGC_DAC_OFFSET (0x800)
#endif

#ifndef DRXK_BANDWIDTH_8MHZ_IN_HZ
#define DRXK_BANDWIDTH_8MHZ_IN_HZ  (0x8B8249L)
#endif

#ifndef DRXK_BANDWIDTH_7MHZ_IN_HZ
#define DRXK_BANDWIDTH_7MHZ_IN_HZ  (0x7A1200L)
#endif

#ifndef DRXK_BANDWIDTH_6MHZ_IN_HZ
#define DRXK_BANDWIDTH_6MHZ_IN_HZ  (0x68A1B6L)
#endif

#ifndef DRXK_QAM_SYMBOLRATE_MAX
#define DRXK_QAM_SYMBOLRATE_MAX         (7233000)
#endif

#define DRXK_BL_ROM_OFFSET_TAPS_DVBT    56
#define DRXK_BL_ROM_OFFSET_TAPS_ITU_A   64
#define DRXK_BL_ROM_OFFSET_TAPS_ITU_C   0x5FE0
#define DRXK_BL_ROM_OFFSET_TAPS_BG      24
#define DRXK_BL_ROM_OFFSET_TAPS_DKILLP  32
#define DRXK_BL_ROM_OFFSET_TAPS_NTSC    40
#define DRXK_BL_ROM_OFFSET_TAPS_FM      48
#define DRXK_BL_ROM_OFFSET_UCODE        0

#define DRXK_BLC_TIMEOUT                100

#define DRXK_BLCC_NR_ELEMENTS_TAPS      2
#define DRXK_BLCC_NR_ELEMENTS_UCODE     6

#define DRXK_BLDC_NR_ELEMENTS_TAPS      28

#ifndef DRXK_OFDM_NE_NOTCH_WIDTH
#define DRXK_OFDM_NE_NOTCH_WIDTH             (4)
#endif

#define DRXK_QAM_SL_SIG_POWER_QAM16       (40960)
#define DRXK_QAM_SL_SIG_POWER_QAM32       (20480)
#define DRXK_QAM_SL_SIG_POWER_QAM64       (43008)
#define DRXK_QAM_SL_SIG_POWER_QAM128      (20992)
#define DRXK_QAM_SL_SIG_POWER_QAM256      (43520)

static unsigned int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages");

#define dprintk(level, fmt, arg...) do {    \
if (debug >= level)       \
 printk(KERN_DEBUG KBUILD_MODNAME ": %s " fmt, __func__, ##arg); \
while (0)

static inline u32 Frac28a(u32 a, u32 c)
{
 int i = 0;
 u32 Q1 = 0;
 u32 R0 = 0;

 R0 = (a % c) << 4; /* 32-28 == 4 shifts possible at max */
 Q1 = a / c;  /*
 * integer part, only the 4 least significant
 * bits will be visible in the result
 */


 /* division using radix 16, 7 nibbles in the result */
 for (i = 0; i < 7; i++) {
  Q1 = (Q1 << 4) | (R0 / c);
  R0 = (R0 % c) << 4;
 }
 /* rounding */
 if ((R0 >> 3) >= c)
  Q1++;

 return Q1;
}

static inline u32 log10times100(u32 value)
{
 return (100L * intlog10(value)) >> 24;
}

/***************************************************************************/
/* I2C **********************************************************************/
/***************************************************************************/

static int drxk_i2c_lock(struct drxk_state *state)
{
 i2c_lock_bus(state->i2c, I2C_LOCK_SEGMENT);
 state->drxk_i2c_exclusive_lock = true;

 return 0;
}

static void drxk_i2c_unlock(struct drxk_state *state)
{
 if (!state->drxk_i2c_exclusive_lock)
  return;

 i2c_unlock_bus(state->i2c, I2C_LOCK_SEGMENT);
 state->drxk_i2c_exclusive_lock = false;
}

static int drxk_i2c_transfer(struct drxk_state *state, struct i2c_msg *msgs,
        unsigned len)
{
 if (state->drxk_i2c_exclusive_lock)
  return __i2c_transfer(state->i2c, msgs, len);
 else
  return i2c_transfer(state->i2c, msgs, len);
}

static int i2c_read1(struct drxk_state *state, u8 adr, u8 *val)
{
 struct i2c_msg msgs[1] = { {.addr = adr, .flags = I2C_M_RD,
        .buf = val, .len = 1}
 };

 return drxk_i2c_transfer(state, msgs, 1);
}

static int i2c_write(struct drxk_state *state, u8 adr, u8 *data, int len)
{
 int status;
 struct i2c_msg msg = {
     .addr = adr, .flags = 0, .buf = data, .len = len };

 dprintk(3, ": %*ph\n", len, data);

 status = drxk_i2c_transfer(state, &msg, 1);
 if (status >= 0 && status != 1)
  status = -EIO;

 if (status < 0)
  pr_err("i2c write error at addr 0x%02x\n", adr);

 return status;
}

static int i2c_read(struct drxk_state *state,
      u8 adr, u8 *msg, int len, u8 *answ, int alen)
{
 int status;
 struct i2c_msg msgs[2] = {
  {.addr = adr, .flags = 0,
        .buf = msg, .len = len},
  {.addr = adr, .flags = I2C_M_RD,
   .buf = answ, .len = alen}
 };

 status = drxk_i2c_transfer(state, msgs, 2);
 if (status != 2) {
  if (debug > 2)
   pr_cont(": ERROR!\n");
  if (status >= 0)
   status = -EIO;

  pr_err("i2c read error at addr 0x%02x\n", adr);
  return status;
 }
 dprintk(3, ": read from %*ph, value = %*ph\n", len, msg, alen, answ);
 return 0;
}

static int read16_flags(struct drxk_state *state, u32 reg, u16 *data, u8 flags)
{
 int status;
 u8 adr = state->demod_address, mm1[4], mm2[2], len;

 if (state->single_master)
  flags |= 0xC0;

 if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
  mm1[0] = (((reg << 1) & 0xFF) | 0x01);
  mm1[1] = ((reg >> 16) & 0xFF);
  mm1[2] = ((reg >> 24) & 0xFF) | flags;
  mm1[3] = ((reg >> 7) & 0xFF);
  len = 4;
 } else {
  mm1[0] = ((reg << 1) & 0xFF);
  mm1[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
  len = 2;
 }
 dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags);
 status = i2c_read(state, adr, mm1, len, mm2, 2);
 if (status < 0)
  return status;
 if (data)
  *data = mm2[0] | (mm2[1] << 8);

 return 0;
}

static int read16(struct drxk_state *state, u32 reg, u16 *data)
{
 return read16_flags(state, reg, data, 0);
}

static int read32_flags(struct drxk_state *state, u32 reg, u32 *data, u8 flags)
{
 int status;
 u8 adr = state->demod_address, mm1[4], mm2[4], len;

 if (state->single_master)
  flags |= 0xC0;

 if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
  mm1[0] = (((reg << 1) & 0xFF) | 0x01);
  mm1[1] = ((reg >> 16) & 0xFF);
  mm1[2] = ((reg >> 24) & 0xFF) | flags;
  mm1[3] = ((reg >> 7) & 0xFF);
  len = 4;
 } else {
  mm1[0] = ((reg << 1) & 0xFF);
  mm1[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
  len = 2;
 }
 dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags);
 status = i2c_read(state, adr, mm1, len, mm2, 4);
 if (status < 0)
  return status;
 if (data)
  *data = mm2[0] | (mm2[1] << 8) |
      (mm2[2] << 16) | (mm2[3] << 24);

 return 0;
}

static int read32(struct drxk_state *state, u32 reg, u32 *data)
{
 return read32_flags(state, reg, data, 0);
}

static int write16_flags(struct drxk_state *state, u32 reg, u16 data, u8 flags)
{
 u8 adr = state->demod_address, mm[6], len;

 if (state->single_master)
  flags |= 0xC0;
 if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
  mm[0] = (((reg << 1) & 0xFF) | 0x01);
  mm[1] = ((reg >> 16) & 0xFF);
  mm[2] = ((reg >> 24) & 0xFF) | flags;
  mm[3] = ((reg >> 7) & 0xFF);
  len = 4;
 } else {
  mm[0] = ((reg << 1) & 0xFF);
  mm[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
  len = 2;
 }
 mm[len] = data & 0xff;
 mm[len + 1] = (data >> 8) & 0xff;

 dprintk(2, "(0x%08x, 0x%04x, 0x%02x)\n", reg, data, flags);
 return i2c_write(state, adr, mm, len + 2);
}

static int write16(struct drxk_state *state, u32 reg, u16 data)
{
 return write16_flags(state, reg, data, 0);
}

static int write32_flags(struct drxk_state *state, u32 reg, u32 data, u8 flags)
{
 u8 adr = state->demod_address, mm[8], len;

 if (state->single_master)
  flags |= 0xC0;
 if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
  mm[0] = (((reg << 1) & 0xFF) | 0x01);
  mm[1] = ((reg >> 16) & 0xFF);
  mm[2] = ((reg >> 24) & 0xFF) | flags;
  mm[3] = ((reg >> 7) & 0xFF);
  len = 4;
 } else {
  mm[0] = ((reg << 1) & 0xFF);
  mm[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
  len = 2;
 }
 mm[len] = data & 0xff;
 mm[len + 1] = (data >> 8) & 0xff;
 mm[len + 2] = (data >> 16) & 0xff;
 mm[len + 3] = (data >> 24) & 0xff;
 dprintk(2, "(0x%08x, 0x%08x, 0x%02x)\n", reg, data, flags);

 return i2c_write(state, adr, mm, len + 4);
}

static int write32(struct drxk_state *state, u32 reg, u32 data)
{
 return write32_flags(state, reg, data, 0);
}

static int write_block(struct drxk_state *state, u32 address,
        const int block_size, const u8 p_block[])
{
 int status = 0, blk_size = block_size;
 u8 flags = 0;

 if (state->single_master)
  flags |= 0xC0;

 while (blk_size > 0) {
  int chunk = blk_size > state->m_chunk_size ?
      state->m_chunk_size : blk_size;
  u8 *adr_buf = &state->chunk[0];
  u32 adr_length = 0;

  if (DRXDAP_FASI_LONG_FORMAT(address) || (flags != 0)) {
   adr_buf[0] = (((address << 1) & 0xFF) | 0x01);
   adr_buf[1] = ((address >> 16) & 0xFF);
   adr_buf[2] = ((address >> 24) & 0xFF);
   adr_buf[3] = ((address >> 7) & 0xFF);
   adr_buf[2] |= flags;
   adr_length = 4;
   if (chunk == state->m_chunk_size)
    chunk -= 2;
  } else {
   adr_buf[0] = ((address << 1) & 0xFF);
   adr_buf[1] = (((address >> 16) & 0x0F) |
         ((address >> 18) & 0xF0));
   adr_length = 2;
  }
  memcpy(&state->chunk[adr_length], p_block, chunk);
  dprintk(2, "(0x%08x, 0x%02x)\n", address, flags);
  if (p_block)
   dprintk(2, "%*ph\n", chunk, p_block);
  status = i2c_write(state, state->demod_address,
       &state->chunk[0], chunk + adr_length);
  if (status < 0) {
   pr_err("%s: i2c write error at addr 0x%02x\n",
          __func__, address);
   break;
  }
  p_block += chunk;
  address += (chunk >> 1);
  blk_size -= chunk;
 }
 return status;
}

#ifndef DRXK_MAX_RETRIES_POWERUP
#define DRXK_MAX_RETRIES_POWERUP 20
#endif

static int power_up_device(struct drxk_state *state)
{
 int status;
 u8 data = 0;
 u16 retry_count = 0;

 dprintk(1, "\n");

 status = i2c_read1(state, state->demod_address, &data);
 if (status < 0) {
  do {
   data = 0;
   status = i2c_write(state, state->demod_address,
        &data, 1);
   usleep_range(10000, 11000);
   retry_count++;
   if (status < 0)
    continue;
   status = i2c_read1(state, state->demod_address,
        &data);
  } while (status < 0 &&
    (retry_count < DRXK_MAX_RETRIES_POWERUP));
  if (status < 0 && retry_count >= DRXK_MAX_RETRIES_POWERUP)
   goto error;
 }

 /* Make sure all clk domains are active */
 status = write16(state, SIO_CC_PWD_MODE__A, SIO_CC_PWD_MODE_LEVEL_NONE);
 if (status < 0)
  goto error;
 status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
 if (status < 0)
  goto error;
 /* Enable pll lock tests */
 status = write16(state, SIO_CC_PLL_LOCK__A, 1);
 if (status < 0)
  goto error;

 state->m_current_power_mode = DRX_POWER_UP;

error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);

 return status;
}


static int init_state(struct drxk_state *state)
{
 /*
 * FIXME: most (all?) of the values below should be moved into
 * struct drxk_config, as they are probably board-specific
 */

 u32 ul_vsb_if_agc_mode = DRXK_AGC_CTRL_AUTO;
 u32 ul_vsb_if_agc_output_level = 0;
 u32 ul_vsb_if_agc_min_level = 0;
 u32 ul_vsb_if_agc_max_level = 0x7FFF;
 u32 ul_vsb_if_agc_speed = 3;

 u32 ul_vsb_rf_agc_mode = DRXK_AGC_CTRL_AUTO;
 u32 ul_vsb_rf_agc_output_level = 0;
 u32 ul_vsb_rf_agc_min_level = 0;
 u32 ul_vsb_rf_agc_max_level = 0x7FFF;
 u32 ul_vsb_rf_agc_speed = 3;
 u32 ul_vsb_rf_agc_top = 9500;
 u32 ul_vsb_rf_agc_cut_off_current = 4000;

 u32 ul_atv_if_agc_mode = DRXK_AGC_CTRL_AUTO;
 u32 ul_atv_if_agc_output_level = 0;
 u32 ul_atv_if_agc_min_level = 0;
 u32 ul_atv_if_agc_max_level = 0;
 u32 ul_atv_if_agc_speed = 3;

 u32 ul_atv_rf_agc_mode = DRXK_AGC_CTRL_OFF;
 u32 ul_atv_rf_agc_output_level = 0;
 u32 ul_atv_rf_agc_min_level = 0;
 u32 ul_atv_rf_agc_max_level = 0;
 u32 ul_atv_rf_agc_top = 9500;
 u32 ul_atv_rf_agc_cut_off_current = 4000;
 u32 ul_atv_rf_agc_speed = 3;

 u32 ulQual83 = DEFAULT_MER_83;
 u32 ulQual93 = DEFAULT_MER_93;

 u32 ul_mpeg_lock_time_out = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
 u32 ul_demod_lock_time_out = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;

 /* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */
 /* io_pad_cfg_mode output mode is drive always */
 /* io_pad_cfg_drive is set to power 2 (23 mA) */
 u32 ul_gpio_cfg = 0x0113;
 u32 ul_invert_ts_clock = 0;
 u32 ul_ts_data_strength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH;
 u32 ul_dvbt_bitrate = 50000000;
 u32 ul_dvbc_bitrate = DRXK_QAM_SYMBOLRATE_MAX * 8;

 u32 ul_insert_rs_byte = 0;

 u32 ul_rf_mirror = 1;
 u32 ul_power_down = 0;

 dprintk(1, "\n");

 state->m_has_lna = false;
 state->m_has_dvbt = false;
 state->m_has_dvbc = false;
 state->m_has_atv = false;
 state->m_has_oob = false;
 state->m_has_audio = false;

 if (!state->m_chunk_size)
  state->m_chunk_size = 124;

 state->m_osc_clock_freq = 0;
 state->m_smart_ant_inverted = false;
 state->m_b_p_down_open_bridge = false;

 /* real system clock frequency in kHz */
 state->m_sys_clock_freq = 151875;
 /* Timing div, 250ns/Psys */
 /* Timing div, = (delay (nano seconds) * sysclk (kHz))/ 1000 */
 state->m_hi_cfg_timing_div = ((state->m_sys_clock_freq / 1000) *
       HI_I2C_DELAY) / 1000;
 /* Clipping */
 if (state->m_hi_cfg_timing_div > SIO_HI_RA_RAM_PAR_2_CFG_DIV__M)
  state->m_hi_cfg_timing_div = SIO_HI_RA_RAM_PAR_2_CFG_DIV__M;
 state->m_hi_cfg_wake_up_key = (state->demod_address << 1);
 /* port/bridge/power down ctrl */
 state->m_hi_cfg_ctrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;

 state->m_b_power_down = (ul_power_down != 0);

 state->m_drxk_a3_patch_code = false;

 /* Init AGC and PGA parameters */
 /* VSB IF */
 state->m_vsb_if_agc_cfg.ctrl_mode = ul_vsb_if_agc_mode;
 state->m_vsb_if_agc_cfg.output_level = ul_vsb_if_agc_output_level;
 state->m_vsb_if_agc_cfg.min_output_level = ul_vsb_if_agc_min_level;
 state->m_vsb_if_agc_cfg.max_output_level = ul_vsb_if_agc_max_level;
 state->m_vsb_if_agc_cfg.speed = ul_vsb_if_agc_speed;
 state->m_vsb_pga_cfg = 140;

 /* VSB RF */
 state->m_vsb_rf_agc_cfg.ctrl_mode = ul_vsb_rf_agc_mode;
 state->m_vsb_rf_agc_cfg.output_level = ul_vsb_rf_agc_output_level;
 state->m_vsb_rf_agc_cfg.min_output_level = ul_vsb_rf_agc_min_level;
 state->m_vsb_rf_agc_cfg.max_output_level = ul_vsb_rf_agc_max_level;
 state->m_vsb_rf_agc_cfg.speed = ul_vsb_rf_agc_speed;
 state->m_vsb_rf_agc_cfg.top = ul_vsb_rf_agc_top;
 state->m_vsb_rf_agc_cfg.cut_off_current = ul_vsb_rf_agc_cut_off_current;
 state->m_vsb_pre_saw_cfg.reference = 0x07;
 state->m_vsb_pre_saw_cfg.use_pre_saw = true;

 state->m_Quality83percent = DEFAULT_MER_83;
 state->m_Quality93percent = DEFAULT_MER_93;
 if (ulQual93 <= 500 && ulQual83 < ulQual93) {
  state->m_Quality83percent = ulQual83;
  state->m_Quality93percent = ulQual93;
 }

 /* ATV IF */
 state->m_atv_if_agc_cfg.ctrl_mode = ul_atv_if_agc_mode;
 state->m_atv_if_agc_cfg.output_level = ul_atv_if_agc_output_level;
 state->m_atv_if_agc_cfg.min_output_level = ul_atv_if_agc_min_level;
 state->m_atv_if_agc_cfg.max_output_level = ul_atv_if_agc_max_level;
 state->m_atv_if_agc_cfg.speed = ul_atv_if_agc_speed;

 /* ATV RF */
 state->m_atv_rf_agc_cfg.ctrl_mode = ul_atv_rf_agc_mode;
 state->m_atv_rf_agc_cfg.output_level = ul_atv_rf_agc_output_level;
 state->m_atv_rf_agc_cfg.min_output_level = ul_atv_rf_agc_min_level;
 state->m_atv_rf_agc_cfg.max_output_level = ul_atv_rf_agc_max_level;
 state->m_atv_rf_agc_cfg.speed = ul_atv_rf_agc_speed;
 state->m_atv_rf_agc_cfg.top = ul_atv_rf_agc_top;
 state->m_atv_rf_agc_cfg.cut_off_current = ul_atv_rf_agc_cut_off_current;
 state->m_atv_pre_saw_cfg.reference = 0x04;
 state->m_atv_pre_saw_cfg.use_pre_saw = true;


 /* DVBT RF */
 state->m_dvbt_rf_agc_cfg.ctrl_mode = DRXK_AGC_CTRL_OFF;
 state->m_dvbt_rf_agc_cfg.output_level = 0;
 state->m_dvbt_rf_agc_cfg.min_output_level = 0;
 state->m_dvbt_rf_agc_cfg.max_output_level = 0xFFFF;
 state->m_dvbt_rf_agc_cfg.top = 0x2100;
 state->m_dvbt_rf_agc_cfg.cut_off_current = 4000;
 state->m_dvbt_rf_agc_cfg.speed = 1;


 /* DVBT IF */
 state->m_dvbt_if_agc_cfg.ctrl_mode = DRXK_AGC_CTRL_AUTO;
 state->m_dvbt_if_agc_cfg.output_level = 0;
 state->m_dvbt_if_agc_cfg.min_output_level = 0;
 state->m_dvbt_if_agc_cfg.max_output_level = 9000;
 state->m_dvbt_if_agc_cfg.top = 13424;
 state->m_dvbt_if_agc_cfg.cut_off_current = 0;
 state->m_dvbt_if_agc_cfg.speed = 3;
 state->m_dvbt_if_agc_cfg.fast_clip_ctrl_delay = 30;
 state->m_dvbt_if_agc_cfg.ingain_tgt_max = 30000;
 /* state->m_dvbtPgaCfg = 140; */

 state->m_dvbt_pre_saw_cfg.reference = 4;
 state->m_dvbt_pre_saw_cfg.use_pre_saw = false;

 /* QAM RF */
 state->m_qam_rf_agc_cfg.ctrl_mode = DRXK_AGC_CTRL_OFF;
 state->m_qam_rf_agc_cfg.output_level = 0;
 state->m_qam_rf_agc_cfg.min_output_level = 6023;
 state->m_qam_rf_agc_cfg.max_output_level = 27000;
 state->m_qam_rf_agc_cfg.top = 0x2380;
 state->m_qam_rf_agc_cfg.cut_off_current = 4000;
 state->m_qam_rf_agc_cfg.speed = 3;

 /* QAM IF */
 state->m_qam_if_agc_cfg.ctrl_mode = DRXK_AGC_CTRL_AUTO;
 state->m_qam_if_agc_cfg.output_level = 0;
 state->m_qam_if_agc_cfg.min_output_level = 0;
 state->m_qam_if_agc_cfg.max_output_level = 9000;
 state->m_qam_if_agc_cfg.top = 0x0511;
 state->m_qam_if_agc_cfg.cut_off_current = 0;
 state->m_qam_if_agc_cfg.speed = 3;
 state->m_qam_if_agc_cfg.ingain_tgt_max = 5119;
 state->m_qam_if_agc_cfg.fast_clip_ctrl_delay = 50;

 state->m_qam_pga_cfg = 140;
 state->m_qam_pre_saw_cfg.reference = 4;
 state->m_qam_pre_saw_cfg.use_pre_saw = false;

 state->m_operation_mode = OM_NONE;
 state->m_drxk_state = DRXK_UNINITIALIZED;

 /* MPEG output configuration */
 state->m_enable_mpeg_output = true/* If TRUE; enable MPEG output */
 state->m_insert_rs_byte = false/* If TRUE; insert RS byte */
 state->m_invert_data = false/* If TRUE; invert DATA signals */
 state->m_invert_err = false/* If TRUE; invert ERR signal */
 state->m_invert_str = false/* If TRUE; invert STR signals */
 state->m_invert_val = false/* If TRUE; invert VAL signals */
 state->m_invert_clk = (ul_invert_ts_clock != 0); /* If TRUE; invert CLK signals */

 /* If TRUE; static MPEG clockrate will be used;
   otherwise clockrate will adapt to the bitrate of the TS */


 state->m_dvbt_bitrate = ul_dvbt_bitrate;
 state->m_dvbc_bitrate = ul_dvbc_bitrate;

 state->m_ts_data_strength = (ul_ts_data_strength & 0x07);

 /* Maximum bitrate in b/s in case static clockrate is selected */
 state->m_mpeg_ts_static_bitrate = 19392658;
 state->m_disable_te_ihandling = false;

 if (ul_insert_rs_byte)
  state->m_insert_rs_byte = true;

 state->m_mpeg_lock_time_out = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
 if (ul_mpeg_lock_time_out < 10000)
  state->m_mpeg_lock_time_out = ul_mpeg_lock_time_out;
 state->m_demod_lock_time_out = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
 if (ul_demod_lock_time_out < 10000)
  state->m_demod_lock_time_out = ul_demod_lock_time_out;

 /* QAM defaults */
 state->m_constellation = DRX_CONSTELLATION_AUTO;
 state->m_qam_interleave_mode = DRXK_QAM_I12_J17;
 state->m_fec_rs_plen = 204 * 8; /* fecRsPlen  annex A */
 state->m_fec_rs_prescale = 1;

 state->m_sqi_speed = DRXK_DVBT_SQI_SPEED_MEDIUM;
 state->m_agcfast_clip_ctrl_delay = 0;

 state->m_gpio_cfg = ul_gpio_cfg;

 state->m_b_power_down = false;
 state->m_current_power_mode = DRX_POWER_DOWN;

 state->m_rfmirror = (ul_rf_mirror == 0);
 state->m_if_agc_pol = false;
 return 0;
}

static int drxx_open(struct drxk_state *state)
{
 int status = 0;
 u32 jtag = 0;
 u16 bid = 0;
 u16 key = 0;

 dprintk(1, "\n");
 /* stop lock indicator process */
 status = write16(state, SCU_RAM_GPIO__A,
    SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
 if (status < 0)
  goto error;
 /* Check device id */
 status = read16(state, SIO_TOP_COMM_KEY__A, &key);
 if (status < 0)
  goto error;
 status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY);
 if (status < 0)
  goto error;
 status = read32(state, SIO_TOP_JTAGID_LO__A, &jtag);
 if (status < 0)
  goto error;
 status = read16(state, SIO_PDR_UIO_IN_HI__A, &bid);
 if (status < 0)
  goto error;
 status = write16(state, SIO_TOP_COMM_KEY__A, key);
error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);
 return status;
}

static int get_device_capabilities(struct drxk_state *state)
{
 u16 sio_pdr_ohw_cfg = 0;
 u32 sio_top_jtagid_lo = 0;
 int status;
 const char *spin = "";

 dprintk(1, "\n");

 /* driver 0.9.0 */
 /* stop lock indicator process */
 status = write16(state, SCU_RAM_GPIO__A,
    SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
 if (status < 0)
  goto error;
 status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY);
 if (status < 0)
  goto error;
 status = read16(state, SIO_PDR_OHW_CFG__A, &sio_pdr_ohw_cfg);
 if (status < 0)
  goto error;
 status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
 if (status < 0)
  goto error;

 switch ((sio_pdr_ohw_cfg & SIO_PDR_OHW_CFG_FREF_SEL__M)) {
 case 0:
  /* ignore (bypass ?) */
  break;
 case 1:
  /* 27 MHz */
  state->m_osc_clock_freq = 27000;
  break;
 case 2:
  /* 20.25 MHz */
  state->m_osc_clock_freq = 20250;
  break;
 case 3:
  /* 4 MHz */
  state->m_osc_clock_freq = 20250;
  break;
 default:
  pr_err("Clock Frequency is unknown\n");
  return -EINVAL;
 }
 /*
Determine device capabilities
Based on pinning v14
*/

 status = read32(state, SIO_TOP_JTAGID_LO__A, &sio_top_jtagid_lo);
 if (status < 0)
  goto error;

 pr_info("status = 0x%08x\n", sio_top_jtagid_lo);

 /* driver 0.9.0 */
 switch ((sio_top_jtagid_lo >> 29) & 0xF) {
 case 0:
  state->m_device_spin = DRXK_SPIN_A1;
  spin = "A1";
  break;
 case 2:
  state->m_device_spin = DRXK_SPIN_A2;
  spin = "A2";
  break;
 case 3:
  state->m_device_spin = DRXK_SPIN_A3;
  spin = "A3";
  break;
 default:
  state->m_device_spin = DRXK_SPIN_UNKNOWN;
  status = -EINVAL;
  pr_err("Spin %d unknown\n", (sio_top_jtagid_lo >> 29) & 0xF);
  goto error2;
 }
 switch ((sio_top_jtagid_lo >> 12) & 0xFF) {
 case 0x13:
  /* typeId = DRX3913K_TYPE_ID */
  state->m_has_lna = false;
  state->m_has_oob = false;
  state->m_has_atv = false;
  state->m_has_audio = false;
  state->m_has_dvbt = true;
  state->m_has_dvbc = true;
  state->m_has_sawsw = true;
  state->m_has_gpio2 = false;
  state->m_has_gpio1 = false;
  state->m_has_irqn = false;
  break;
 case 0x15:
  /* typeId = DRX3915K_TYPE_ID */
  state->m_has_lna = false;
  state->m_has_oob = false;
  state->m_has_atv = true;
  state->m_has_audio = false;
  state->m_has_dvbt = true;
  state->m_has_dvbc = false;
  state->m_has_sawsw = true;
  state->m_has_gpio2 = true;
  state->m_has_gpio1 = true;
  state->m_has_irqn = false;
  break;
 case 0x16:
  /* typeId = DRX3916K_TYPE_ID */
  state->m_has_lna = false;
  state->m_has_oob = false;
  state->m_has_atv = true;
  state->m_has_audio = false;
  state->m_has_dvbt = true;
  state->m_has_dvbc = false;
  state->m_has_sawsw = true;
  state->m_has_gpio2 = true;
  state->m_has_gpio1 = true;
  state->m_has_irqn = false;
  break;
 case 0x18:
  /* typeId = DRX3918K_TYPE_ID */
  state->m_has_lna = false;
  state->m_has_oob = false;
  state->m_has_atv = true;
  state->m_has_audio = true;
  state->m_has_dvbt = true;
  state->m_has_dvbc = false;
  state->m_has_sawsw = true;
  state->m_has_gpio2 = true;
  state->m_has_gpio1 = true;
  state->m_has_irqn = false;
  break;
 case 0x21:
  /* typeId = DRX3921K_TYPE_ID */
  state->m_has_lna = false;
  state->m_has_oob = false;
  state->m_has_atv = true;
  state->m_has_audio = true;
  state->m_has_dvbt = true;
  state->m_has_dvbc = true;
  state->m_has_sawsw = true;
  state->m_has_gpio2 = true;
  state->m_has_gpio1 = true;
  state->m_has_irqn = false;
  break;
 case 0x23:
  /* typeId = DRX3923K_TYPE_ID */
  state->m_has_lna = false;
  state->m_has_oob = false;
  state->m_has_atv = true;
  state->m_has_audio = true;
  state->m_has_dvbt = true;
  state->m_has_dvbc = true;
  state->m_has_sawsw = true;
  state->m_has_gpio2 = true;
  state->m_has_gpio1 = true;
  state->m_has_irqn = false;
  break;
 case 0x25:
  /* typeId = DRX3925K_TYPE_ID */
  state->m_has_lna = false;
  state->m_has_oob = false;
  state->m_has_atv = true;
  state->m_has_audio = true;
  state->m_has_dvbt = true;
  state->m_has_dvbc = true;
  state->m_has_sawsw = true;
  state->m_has_gpio2 = true;
  state->m_has_gpio1 = true;
  state->m_has_irqn = false;
  break;
 case 0x26:
  /* typeId = DRX3926K_TYPE_ID */
  state->m_has_lna = false;
  state->m_has_oob = false;
  state->m_has_atv = true;
  state->m_has_audio = false;
  state->m_has_dvbt = true;
  state->m_has_dvbc = true;
  state->m_has_sawsw = true;
  state->m_has_gpio2 = true;
  state->m_has_gpio1 = true;
  state->m_has_irqn = false;
  break;
 default:
  pr_err("DeviceID 0x%02x not supported\n",
   ((sio_top_jtagid_lo >> 12) & 0xFF));
  status = -EINVAL;
  goto error2;
 }

 pr_info("detected a drx-39%02xk, spin %s, xtal %d.%03d MHz\n",
        ((sio_top_jtagid_lo >> 12) & 0xFF), spin,
        state->m_osc_clock_freq / 1000,
        state->m_osc_clock_freq % 1000);

error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);

error2:
 return status;
}

static int hi_command(struct drxk_state *state, u16 cmd, u16 *p_result)
{
 int status;
 bool powerdown_cmd;

 dprintk(1, "\n");

 /* Write command */
 status = write16(state, SIO_HI_RA_RAM_CMD__A, cmd);
 if (status < 0)
  goto error;
 if (cmd == SIO_HI_RA_RAM_CMD_RESET)
  usleep_range(1000, 2000);

 powerdown_cmd =
     (bool) ((cmd == SIO_HI_RA_RAM_CMD_CONFIG) &&
      ((state->m_hi_cfg_ctrl) &
       SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M) ==
      SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ);
 if (!powerdown_cmd) {
  /* Wait until command rdy */
  u32 retry_count = 0;
  u16 wait_cmd;

  do {
   usleep_range(1000, 2000);
   retry_count += 1;
   status = read16(state, SIO_HI_RA_RAM_CMD__A,
       &wait_cmd);
  } while ((status < 0 || wait_cmd) && (retry_count < DRXK_MAX_RETRIES));
  if (status < 0)
   goto error;
  status = read16(state, SIO_HI_RA_RAM_RES__A, p_result);
 }
error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);

 return status;
}

static int hi_cfg_command(struct drxk_state *state)
{
 int status;

 dprintk(1, "\n");

 mutex_lock(&state->mutex);

 status = write16(state, SIO_HI_RA_RAM_PAR_6__A,
    state->m_hi_cfg_timeout);
 if (status < 0)
  goto error;
 status = write16(state, SIO_HI_RA_RAM_PAR_5__A,
    state->m_hi_cfg_ctrl);
 if (status < 0)
  goto error;
 status = write16(state, SIO_HI_RA_RAM_PAR_4__A,
    state->m_hi_cfg_wake_up_key);
 if (status < 0)
  goto error;
 status = write16(state, SIO_HI_RA_RAM_PAR_3__A,
    state->m_hi_cfg_bridge_delay);
 if (status < 0)
  goto error;
 status = write16(state, SIO_HI_RA_RAM_PAR_2__A,
    state->m_hi_cfg_timing_div);
 if (status < 0)
  goto error;
 status = write16(state, SIO_HI_RA_RAM_PAR_1__A,
    SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
 if (status < 0)
  goto error;
 status = hi_command(state, SIO_HI_RA_RAM_CMD_CONFIG, NULL);
 if (status < 0)
  goto error;

 state->m_hi_cfg_ctrl &= ~SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
error:
 mutex_unlock(&state->mutex);
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);
 return status;
}

static int init_hi(struct drxk_state *state)
{
 dprintk(1, "\n");

 state->m_hi_cfg_wake_up_key = (state->demod_address << 1);
 state->m_hi_cfg_timeout = 0x96FF;
 /* port/bridge/power down ctrl */
 state->m_hi_cfg_ctrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;

 return hi_cfg_command(state);
}

static int mpegts_configure_pins(struct drxk_state *state, bool mpeg_enable)
{
 int status;
 u16 sio_pdr_mclk_cfg = 0;
 u16 sio_pdr_mdx_cfg = 0;
 u16 err_cfg = 0;

 dprintk(1, ": mpeg %s, %s mode\n",
  mpeg_enable ? "enable" : "disable",
  state->m_enable_parallel ? "parallel" : "serial");

 /* stop lock indicator process */
 status = write16(state, SCU_RAM_GPIO__A,
    SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
 if (status < 0)
  goto error;

 /*  MPEG TS pad configuration */
 status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY);
 if (status < 0)
  goto error;

 if (!mpeg_enable) {
  /*  Set MPEG TS pads to inputmode */
  status = write16(state, SIO_PDR_MSTRT_CFG__A, 0x0000);
  if (status < 0)
   goto error;
  status = write16(state, SIO_PDR_MERR_CFG__A, 0x0000);
  if (status < 0)
   goto error;
  status = write16(state, SIO_PDR_MCLK_CFG__A, 0x0000);
  if (status < 0)
   goto error;
  status = write16(state, SIO_PDR_MVAL_CFG__A, 0x0000);
  if (status < 0)
   goto error;
  status = write16(state, SIO_PDR_MD0_CFG__A, 0x0000);
  if (status < 0)
   goto error;
  status = write16(state, SIO_PDR_MD1_CFG__A, 0x0000);
  if (status < 0)
   goto error;
  status = write16(state, SIO_PDR_MD2_CFG__A, 0x0000);
  if (status < 0)
   goto error;
  status = write16(state, SIO_PDR_MD3_CFG__A, 0x0000);
  if (status < 0)
   goto error;
  status = write16(state, SIO_PDR_MD4_CFG__A, 0x0000);
  if (status < 0)
   goto error;
  status = write16(state, SIO_PDR_MD5_CFG__A, 0x0000);
  if (status < 0)
   goto error;
  status = write16(state, SIO_PDR_MD6_CFG__A, 0x0000);
  if (status < 0)
   goto error;
  status = write16(state, SIO_PDR_MD7_CFG__A, 0x0000);
  if (status < 0)
   goto error;
 } else {
  /* Enable MPEG output */
  sio_pdr_mdx_cfg =
   ((state->m_ts_data_strength <<
   SIO_PDR_MD0_CFG_DRIVE__B) | 0x0003);
  sio_pdr_mclk_cfg = ((state->m_ts_clockk_strength <<
     SIO_PDR_MCLK_CFG_DRIVE__B) |
     0x0003);

  status = write16(state, SIO_PDR_MSTRT_CFG__A, sio_pdr_mdx_cfg);
  if (status < 0)
   goto error;

  if (state->enable_merr_cfg)
   err_cfg = sio_pdr_mdx_cfg;

  status = write16(state, SIO_PDR_MERR_CFG__A, err_cfg);
  if (status < 0)
   goto error;
  status = write16(state, SIO_PDR_MVAL_CFG__A, err_cfg);
  if (status < 0)
   goto error;

  if (state->m_enable_parallel) {
   /* parallel -> enable MD1 to MD7 */
   status = write16(state, SIO_PDR_MD1_CFG__A,
      sio_pdr_mdx_cfg);
   if (status < 0)
    goto error;
   status = write16(state, SIO_PDR_MD2_CFG__A,
      sio_pdr_mdx_cfg);
   if (status < 0)
    goto error;
   status = write16(state, SIO_PDR_MD3_CFG__A,
      sio_pdr_mdx_cfg);
   if (status < 0)
    goto error;
   status = write16(state, SIO_PDR_MD4_CFG__A,
      sio_pdr_mdx_cfg);
   if (status < 0)
    goto error;
   status = write16(state, SIO_PDR_MD5_CFG__A,
      sio_pdr_mdx_cfg);
   if (status < 0)
    goto error;
   status = write16(state, SIO_PDR_MD6_CFG__A,
      sio_pdr_mdx_cfg);
   if (status < 0)
    goto error;
   status = write16(state, SIO_PDR_MD7_CFG__A,
      sio_pdr_mdx_cfg);
   if (status < 0)
    goto error;
  } else {
   sio_pdr_mdx_cfg = ((state->m_ts_data_strength <<
      SIO_PDR_MD0_CFG_DRIVE__B)
     | 0x0003);
   /* serial -> disable MD1 to MD7 */
   status = write16(state, SIO_PDR_MD1_CFG__A, 0x0000);
   if (status < 0)
    goto error;
   status = write16(state, SIO_PDR_MD2_CFG__A, 0x0000);
   if (status < 0)
    goto error;
   status = write16(state, SIO_PDR_MD3_CFG__A, 0x0000);
   if (status < 0)
    goto error;
   status = write16(state, SIO_PDR_MD4_CFG__A, 0x0000);
   if (status < 0)
    goto error;
   status = write16(state, SIO_PDR_MD5_CFG__A, 0x0000);
   if (status < 0)
    goto error;
   status = write16(state, SIO_PDR_MD6_CFG__A, 0x0000);
   if (status < 0)
    goto error;
   status = write16(state, SIO_PDR_MD7_CFG__A, 0x0000);
   if (status < 0)
    goto error;
  }
  status = write16(state, SIO_PDR_MCLK_CFG__A, sio_pdr_mclk_cfg);
  if (status < 0)
   goto error;
  status = write16(state, SIO_PDR_MD0_CFG__A, sio_pdr_mdx_cfg);
  if (status < 0)
   goto error;
 }
 /*  Enable MB output over MPEG pads and ctl input */
 status = write16(state, SIO_PDR_MON_CFG__A, 0x0000);
 if (status < 0)
  goto error;
 /*  Write nomagic word to enable pdr reg write */
 status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);
 return status;
}

static int mpegts_disable(struct drxk_state *state)
{
 dprintk(1, "\n");

 return mpegts_configure_pins(state, false);
}

static int bl_chain_cmd(struct drxk_state *state,
        u16 rom_offset, u16 nr_of_elements, u32 time_out)
{
 u16 bl_status = 0;
 int status;
 unsigned long end;

 dprintk(1, "\n");
 mutex_lock(&state->mutex);
 status = write16(state, SIO_BL_MODE__A, SIO_BL_MODE_CHAIN);
 if (status < 0)
  goto error;
 status = write16(state, SIO_BL_CHAIN_ADDR__A, rom_offset);
 if (status < 0)
  goto error;
 status = write16(state, SIO_BL_CHAIN_LEN__A, nr_of_elements);
 if (status < 0)
  goto error;
 status = write16(state, SIO_BL_ENABLE__A, SIO_BL_ENABLE_ON);
 if (status < 0)
  goto error;

 end = jiffies + msecs_to_jiffies(time_out);
 do {
  usleep_range(1000, 2000);
  status = read16(state, SIO_BL_STATUS__A, &bl_status);
  if (status < 0)
   goto error;
 } while ((bl_status == 0x1) &&
   ((time_is_after_jiffies(end))));

 if (bl_status == 0x1) {
  pr_err("SIO not ready\n");
  status = -EINVAL;
  goto error2;
 }
error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);
error2:
 mutex_unlock(&state->mutex);
 return status;
}


static int download_microcode(struct drxk_state *state,
        const u8 p_mc_image[], u32 length)
{
 const u8 *p_src = p_mc_image;
 u32 address;
 u16 n_blocks;
 u16 block_size;
 u32 offset = 0;
 u32 i;
 int status = 0;

 dprintk(1, "\n");

 /* down the drain (we don't care about MAGIC_WORD) */
#if 0
 /* For future reference */
 drain = (p_src[0] << 8) | p_src[1];
#endif
 p_src += sizeof(u16);
 offset += sizeof(u16);
 n_blocks = (p_src[0] << 8) | p_src[1];
 p_src += sizeof(u16);
 offset += sizeof(u16);

 for (i = 0; i < n_blocks; i += 1) {
  address = (p_src[0] << 24) | (p_src[1] << 16) |
      (p_src[2] << 8) | p_src[3];
  p_src += sizeof(u32);
  offset += sizeof(u32);

  block_size = ((p_src[0] << 8) | p_src[1]) * sizeof(u16);
  p_src += sizeof(u16);
  offset += sizeof(u16);

#if 0
  /* For future reference */
  flags = (p_src[0] << 8) | p_src[1];
#endif
  p_src += sizeof(u16);
  offset += sizeof(u16);

#if 0
  /* For future reference */
  block_crc = (p_src[0] << 8) | p_src[1];
#endif
  p_src += sizeof(u16);
  offset += sizeof(u16);

  if (offset + block_size > length) {
   pr_err("Firmware is corrupted.\n");
   return -EINVAL;
  }

  status = write_block(state, address, block_size, p_src);
  if (status < 0) {
   pr_err("Error %d while loading firmware\n", status);
   break;
  }
  p_src += block_size;
  offset += block_size;
 }
 return status;
}

static int dvbt_enable_ofdm_token_ring(struct drxk_state *state, bool enable)
{
 int status;
 u16 data = 0;
 u16 desired_ctrl = SIO_OFDM_SH_OFDM_RING_ENABLE_ON;
 u16 desired_status = SIO_OFDM_SH_OFDM_RING_STATUS_ENABLED;
 unsigned long end;

 dprintk(1, "\n");

 if (!enable) {
  desired_ctrl = SIO_OFDM_SH_OFDM_RING_ENABLE_OFF;
  desired_status = SIO_OFDM_SH_OFDM_RING_STATUS_DOWN;
 }

 status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data);
 if (status >= 0 && data == desired_status) {
  /* tokenring already has correct status */
  return status;
 }
 /* Disable/enable dvbt tokenring bridge   */
 status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, desired_ctrl);

 end = jiffies + msecs_to_jiffies(DRXK_OFDM_TR_SHUTDOWN_TIMEOUT);
 do {
  status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data);
  if ((status >= 0 && data == desired_status)
      || time_is_after_jiffies(end))
   break;
  usleep_range(1000, 2000);
 } while (1);
 if (data != desired_status) {
  pr_err("SIO not ready\n");
  return -EINVAL;
 }
 return status;
}

static int mpegts_stop(struct drxk_state *state)
{
 int status = 0;
 u16 fec_oc_snc_mode = 0;
 u16 fec_oc_ipr_mode = 0;

 dprintk(1, "\n");

 /* Graceful shutdown (byte boundaries) */
 status = read16(state, FEC_OC_SNC_MODE__A, &fec_oc_snc_mode);
 if (status < 0)
  goto error;
 fec_oc_snc_mode |= FEC_OC_SNC_MODE_SHUTDOWN__M;
 status = write16(state, FEC_OC_SNC_MODE__A, fec_oc_snc_mode);
 if (status < 0)
  goto error;

 /* Suppress MCLK during absence of data */
 status = read16(state, FEC_OC_IPR_MODE__A, &fec_oc_ipr_mode);
 if (status < 0)
  goto error;
 fec_oc_ipr_mode |= FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M;
 status = write16(state, FEC_OC_IPR_MODE__A, fec_oc_ipr_mode);

error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);

 return status;
}

static int scu_command(struct drxk_state *state,
         u16 cmd, u8 parameter_len,
         u16 *parameter, u8 result_len, u16 *result)
{
#if (SCU_RAM_PARAM_0__A - SCU_RAM_PARAM_15__A) != 15
#error DRXK register mapping no longer compatible with this routine!
#endif
 u16 cur_cmd = 0;
 int status = -EINVAL;
 unsigned long end;
 u8 buffer[34];
 int cnt = 0, ii;
 const char *p;
 char errname[30];

 dprintk(1, "\n");

 if ((cmd == 0) || ((parameter_len > 0) && (parameter == NULL)) ||
     ((result_len > 0) && (result == NULL))) {
  pr_err("Error %d on %s\n", status, __func__);
  return status;
 }

 mutex_lock(&state->mutex);

 /* assume that the command register is ready
since it is checked afterwards */

 if (parameter) {
  for (ii = parameter_len - 1; ii >= 0; ii -= 1) {
   buffer[cnt++] = (parameter[ii] & 0xFF);
   buffer[cnt++] = ((parameter[ii] >> 8) & 0xFF);
  }
 }
 buffer[cnt++] = (cmd & 0xFF);
 buffer[cnt++] = ((cmd >> 8) & 0xFF);

 write_block(state, SCU_RAM_PARAM_0__A -
   (parameter_len - 1), cnt, buffer);
 /* Wait until SCU has processed command */
 end = jiffies + msecs_to_jiffies(DRXK_MAX_WAITTIME);
 do {
  usleep_range(1000, 2000);
  status = read16(state, SCU_RAM_COMMAND__A, &cur_cmd);
  if (status < 0)
   goto error;
 } while (!(cur_cmd == DRX_SCU_READY) && (time_is_after_jiffies(end)));
 if (cur_cmd != DRX_SCU_READY) {
  pr_err("SCU not ready\n");
  status = -EIO;
  goto error2;
 }
 /* read results */
 if ((result_len > 0) && (result != NULL)) {
  s16 err;
  int ii;

  for (ii = result_len - 1; ii >= 0; ii -= 1) {
   status = read16(state, SCU_RAM_PARAM_0__A - ii,
     &result[ii]);
   if (status < 0)
    goto error;
  }

  /* Check if an error was reported by SCU */
  err = (s16)result[0];
  if (err >= 0)
   goto error;

  /* check for the known error codes */
  switch (err) {
  case SCU_RESULT_UNKCMD:
   p = "SCU_RESULT_UNKCMD";
   break;
  case SCU_RESULT_UNKSTD:
   p = "SCU_RESULT_UNKSTD";
   break;
  case SCU_RESULT_SIZE:
   p = "SCU_RESULT_SIZE";
   break;
  case SCU_RESULT_INVPAR:
   p = "SCU_RESULT_INVPAR";
   break;
  default/* Other negative values are errors */
   sprintf(errname, "ERROR: %d\n", err);
   p = errname;
  }
  pr_err("%s while sending cmd 0x%04x with params:", p, cmd);
  print_hex_dump_bytes("drxk: ", DUMP_PREFIX_NONE, buffer, cnt);
  status = -EINVAL;
  goto error2;
 }

error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);
error2:
 mutex_unlock(&state->mutex);
 return status;
}

static int set_iqm_af(struct drxk_state *state, bool active)
{
 u16 data = 0;
 int status;

 dprintk(1, "\n");

 /* Configure IQM */
 status = read16(state, IQM_AF_STDBY__A, &data);
 if (status < 0)
  goto error;

 if (!active) {
  data |= (IQM_AF_STDBY_STDBY_ADC_STANDBY
    | IQM_AF_STDBY_STDBY_AMP_STANDBY
    | IQM_AF_STDBY_STDBY_PD_STANDBY
    | IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY
    | IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY);
 } else {
  data &= ((~IQM_AF_STDBY_STDBY_ADC_STANDBY)
    & (~IQM_AF_STDBY_STDBY_AMP_STANDBY)
    & (~IQM_AF_STDBY_STDBY_PD_STANDBY)
    & (~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY)
    & (~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY)
   );
 }
 status = write16(state, IQM_AF_STDBY__A, data);

error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);
 return status;
}

static int ctrl_power_mode(struct drxk_state *state, enum drx_power_mode *mode)
{
 int status = 0;
 u16 sio_cc_pwd_mode = 0;

 dprintk(1, "\n");

 /* Check arguments */
 if (mode == NULL)
  return -EINVAL;

 switch (*mode) {
 case DRX_POWER_UP:
  sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_NONE;
  break;
 case DRXK_POWER_DOWN_OFDM:
  sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_OFDM;
  break;
 case DRXK_POWER_DOWN_CORE:
  sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_CLOCK;
  break;
 case DRXK_POWER_DOWN_PLL:
  sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_PLL;
  break;
 case DRX_POWER_DOWN:
  sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_OSC;
  break;
 default:
  /* Unknown sleep mode */
  return -EINVAL;
 }

 /* If already in requested power mode, do nothing */
 if (state->m_current_power_mode == *mode)
  return 0;

 /* For next steps make sure to start from DRX_POWER_UP mode */
 if (state->m_current_power_mode != DRX_POWER_UP) {
  status = power_up_device(state);
  if (status < 0)
   goto error;
  status = dvbt_enable_ofdm_token_ring(state, true);
  if (status < 0)
   goto error;
 }

 if (*mode == DRX_POWER_UP) {
  /* Restore analog & pin configuration */
 } else {
  /* Power down to requested mode */
  /* Backup some register settings */
  /* Set pins with possible pull-ups connected
   to them in input mode */

  /* Analog power down */
  /* ADC power down */
  /* Power down device */
  /* stop all comm_exec */
  /* Stop and power down previous standard */
  switch (state->m_operation_mode) {
  case OM_DVBT:
   status = mpegts_stop(state);
   if (status < 0)
    goto error;
   status = power_down_dvbt(state, false);
   if (status < 0)
    goto error;
   break;
  case OM_QAM_ITU_A:
  case OM_QAM_ITU_C:
   status = mpegts_stop(state);
   if (status < 0)
    goto error;
   status = power_down_qam(state);
   if (status < 0)
    goto error;
   break;
  default:
   break;
  }
  status = dvbt_enable_ofdm_token_ring(state, false);
  if (status < 0)
   goto error;
  status = write16(state, SIO_CC_PWD_MODE__A, sio_cc_pwd_mode);
  if (status < 0)
   goto error;
  status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
  if (status < 0)
   goto error;

  if (*mode != DRXK_POWER_DOWN_OFDM) {
   state->m_hi_cfg_ctrl |=
    SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
   status = hi_cfg_command(state);
   if (status < 0)
    goto error;
  }
 }
 state->m_current_power_mode = *mode;

error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);

 return status;
}

static int power_down_dvbt(struct drxk_state *state, bool set_power_mode)
{
 enum drx_power_mode power_mode = DRXK_POWER_DOWN_OFDM;
 u16 cmd_result = 0;
 u16 data = 0;
 int status;

 dprintk(1, "\n");

 status = read16(state, SCU_COMM_EXEC__A, &data);
 if (status < 0)
  goto error;
 if (data == SCU_COMM_EXEC_ACTIVE) {
  /* Send OFDM stop command */
  status = scu_command(state,
         SCU_RAM_COMMAND_STANDARD_OFDM
         | SCU_RAM_COMMAND_CMD_DEMOD_STOP,
         0, NULL, 1, &cmd_result);
  if (status < 0)
   goto error;
  /* Send OFDM reset command */
  status = scu_command(state,
         SCU_RAM_COMMAND_STANDARD_OFDM
         | SCU_RAM_COMMAND_CMD_DEMOD_RESET,
         0, NULL, 1, &cmd_result);
  if (status < 0)
   goto error;
 }

 /* Reset datapath for OFDM, processors first */
 status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP);
 if (status < 0)
  goto error;
 status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP);
 if (status < 0)
  goto error;
 status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP);
 if (status < 0)
  goto error;

 /* powerdown AFE                   */
 status = set_iqm_af(state, false);
 if (status < 0)
  goto error;

 /* powerdown to OFDM mode          */
 if (set_power_mode) {
  status = ctrl_power_mode(state, &power_mode);
  if (status < 0)
   goto error;
 }
error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);
 return status;
}

static int setoperation_mode(struct drxk_state *state,
       enum operation_mode o_mode)
{
 int status = 0;

 dprintk(1, "\n");
 /*
   Stop and power down previous standard
   TODO investigate total power down instead of partial
   power down depending on "previous" standard.
 */


 /* disable HW lock indicator */
 status = write16(state, SCU_RAM_GPIO__A,
    SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
 if (status < 0)
  goto error;

 /* Device is already at the required mode */
 if (state->m_operation_mode == o_mode)
  return 0;

 switch (state->m_operation_mode) {
  /* OM_NONE was added for start up */
 case OM_NONE:
  break;
 case OM_DVBT:
  status = mpegts_stop(state);
  if (status < 0)
   goto error;
  status = power_down_dvbt(state, true);
  if (status < 0)
   goto error;
  state->m_operation_mode = OM_NONE;
  break;
 case OM_QAM_ITU_A:
 case OM_QAM_ITU_C:
  status = mpegts_stop(state);
  if (status < 0)
   goto error;
  status = power_down_qam(state);
  if (status < 0)
   goto error;
  state->m_operation_mode = OM_NONE;
  break;
 case OM_QAM_ITU_B:
 default:
  status = -EINVAL;
  goto error;
 }

 /*
Power up new standard
*/

 switch (o_mode) {
 case OM_DVBT:
  dprintk(1, ": DVB-T\n");
  state->m_operation_mode = o_mode;
  status = set_dvbt_standard(state, o_mode);
  if (status < 0)
   goto error;
  break;
 case OM_QAM_ITU_A:
 case OM_QAM_ITU_C:
  dprintk(1, ": DVB-C Annex %c\n",
   (state->m_operation_mode == OM_QAM_ITU_A) ? 'A' : 'C');
  state->m_operation_mode = o_mode;
  status = set_qam_standard(state, o_mode);
  if (status < 0)
   goto error;
  break;
 case OM_QAM_ITU_B:
 default:
  status = -EINVAL;
 }
error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);
 return status;
}

static int start(struct drxk_state *state, s32 offset_freq,
   s32 intermediate_frequency)
{
 int status = -EINVAL;

 u16 i_freqk_hz;
 s32 offsetk_hz = offset_freq / 1000;

 dprintk(1, "\n");
 if (state->m_drxk_state != DRXK_STOPPED &&
  state->m_drxk_state != DRXK_DTV_STARTED)
  goto error;

 state->m_b_mirror_freq_spect = (state->props.inversion == INVERSION_ON);

 if (intermediate_frequency < 0) {
  state->m_b_mirror_freq_spect = !state->m_b_mirror_freq_spect;
  intermediate_frequency = -intermediate_frequency;
 }

 switch (state->m_operation_mode) {
 case OM_QAM_ITU_A:
 case OM_QAM_ITU_C:
  i_freqk_hz = (intermediate_frequency / 1000);
  status = set_qam(state, i_freqk_hz, offsetk_hz);
  if (status < 0)
   goto error;
  state->m_drxk_state = DRXK_DTV_STARTED;
  break;
 case OM_DVBT:
  i_freqk_hz = (intermediate_frequency / 1000);
  status = mpegts_stop(state);
  if (status < 0)
   goto error;
  status = set_dvbt(state, i_freqk_hz, offsetk_hz);
  if (status < 0)
   goto error;
  status = dvbt_start(state);
  if (status < 0)
   goto error;
  state->m_drxk_state = DRXK_DTV_STARTED;
  break;
 default:
  break;
 }
error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);
 return status;
}

static int shut_down(struct drxk_state *state)
{
 dprintk(1, "\n");

 mpegts_stop(state);
 return 0;
}

static int get_lock_status(struct drxk_state *state, u32 *p_lock_status)
{
 int status = -EINVAL;

 dprintk(1, "\n");

 if (p_lock_status == NULL)
  goto error;

 *p_lock_status = NOT_LOCKED;

 /* define the SCU command code */
 switch (state->m_operation_mode) {
 case OM_QAM_ITU_A:
 case OM_QAM_ITU_B:
 case OM_QAM_ITU_C:
  status = get_qam_lock_status(state, p_lock_status);
  break;
 case OM_DVBT:
  status = get_dvbt_lock_status(state, p_lock_status);
  break;
 default:
  pr_debug("Unsupported operation mode %d in %s\n",
   state->m_operation_mode, __func__);
  return 0;
 }
error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);
 return status;
}

static int mpegts_start(struct drxk_state *state)
{
 int status;

 u16 fec_oc_snc_mode = 0;

 /* Allow OC to sync again */
 status = read16(state, FEC_OC_SNC_MODE__A, &fec_oc_snc_mode);
 if (status < 0)
  goto error;
 fec_oc_snc_mode &= ~FEC_OC_SNC_MODE_SHUTDOWN__M;
 status = write16(state, FEC_OC_SNC_MODE__A, fec_oc_snc_mode);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_SNC_UNLOCK__A, 1);
error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);
 return status;
}

static int mpegts_dto_init(struct drxk_state *state)
{
 int status;

 dprintk(1, "\n");

 /* Rate integration settings */
 status = write16(state, FEC_OC_RCN_CTL_STEP_LO__A, 0x0000);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_RCN_CTL_STEP_HI__A, 0x000C);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_RCN_GAIN__A, 0x000A);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_AVR_PARM_A__A, 0x0008);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_AVR_PARM_B__A, 0x0006);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_TMD_HI_MARGIN__A, 0x0680);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_TMD_LO_MARGIN__A, 0x0080);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_TMD_COUNT__A, 0x03F4);
 if (status < 0)
  goto error;

 /* Additional configuration */
 status = write16(state, FEC_OC_OCR_INVERT__A, 0);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_SNC_LWM__A, 2);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_SNC_HWM__A, 12);
error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);

 return status;
}

static int mpegts_dto_setup(struct drxk_state *state,
     enum operation_mode o_mode)
{
 int status;

 u16 fec_oc_reg_mode = 0; /* FEC_OC_MODE       register value */
 u16 fec_oc_reg_ipr_mode = 0; /* FEC_OC_IPR_MODE   register value */
 u16 fec_oc_dto_mode = 0; /* FEC_OC_IPR_INVERT register value */
 u16 fec_oc_fct_mode = 0; /* FEC_OC_IPR_INVERT register value */
 u16 fec_oc_dto_period = 2; /* FEC_OC_IPR_INVERT register value */
 u16 fec_oc_dto_burst_len = 188; /* FEC_OC_IPR_INVERT register value */
 u32 fec_oc_rcn_ctl_rate = 0; /* FEC_OC_IPR_INVERT register value */
 u16 fec_oc_tmd_mode = 0;
 u16 fec_oc_tmd_int_upd_rate = 0;
 u32 max_bit_rate = 0;
 bool static_clk = false;

 dprintk(1, "\n");

 /* Check insertion of the Reed-Solomon parity bytes */
 status = read16(state, FEC_OC_MODE__A, &fec_oc_reg_mode);
 if (status < 0)
  goto error;
 status = read16(state, FEC_OC_IPR_MODE__A, &fec_oc_reg_ipr_mode);
 if (status < 0)
  goto error;
 fec_oc_reg_mode &= (~FEC_OC_MODE_PARITY__M);
 fec_oc_reg_ipr_mode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M);
 if (state->m_insert_rs_byte) {
  /* enable parity symbol forward */
  fec_oc_reg_mode |= FEC_OC_MODE_PARITY__M;
  /* MVAL disable during parity bytes */
  fec_oc_reg_ipr_mode |= FEC_OC_IPR_MODE_MVAL_DIS_PAR__M;
  /* TS burst length to 204 */
  fec_oc_dto_burst_len = 204;
 }

 /* Check serial or parallel output */
 fec_oc_reg_ipr_mode &= (~(FEC_OC_IPR_MODE_SERIAL__M));
 if (!state->m_enable_parallel) {
  /* MPEG data output is serial -> set ipr_mode[0] */
  fec_oc_reg_ipr_mode |= FEC_OC_IPR_MODE_SERIAL__M;
 }

 switch (o_mode) {
 case OM_DVBT:
  max_bit_rate = state->m_dvbt_bitrate;
  fec_oc_tmd_mode = 3;
  fec_oc_rcn_ctl_rate = 0xC00000;
  static_clk = state->m_dvbt_static_clk;
  break;
 case OM_QAM_ITU_A:
 case OM_QAM_ITU_C:
  fec_oc_tmd_mode = 0x0004;
  fec_oc_rcn_ctl_rate = 0xD2B4EE; /* good for >63 Mb/s */
  max_bit_rate = state->m_dvbc_bitrate;
  static_clk = state->m_dvbc_static_clk;
  break;
 default:
  status = -EINVAL;
 }  /* switch (standard) */
 if (status < 0)
  goto error;

 /* Configure DTO's */
 if (static_clk) {
  u32 bit_rate = 0;

  /* Rational DTO for MCLK source (static MCLK rate),
Dynamic DTO for optimal grouping
(avoid intra-packet gaps),
DTO offset enable to sync TS burst with MSTRT */

  fec_oc_dto_mode = (FEC_OC_DTO_MODE_DYNAMIC__M |
    FEC_OC_DTO_MODE_OFFSET_ENABLE__M);
  fec_oc_fct_mode = (FEC_OC_FCT_MODE_RAT_ENA__M |
    FEC_OC_FCT_MODE_VIRT_ENA__M);

  /* Check user defined bitrate */
  bit_rate = max_bit_rate;
  if (bit_rate > 75900000UL) { /* max is 75.9 Mb/s */
   bit_rate = 75900000UL;
  }
  /* Rational DTO period:
dto_period = (Fsys / bitrate) - 2

result should be floored,
to make sure >= requested bitrate
*/

  fec_oc_dto_period = (u16) (((state->m_sys_clock_freq)
      * 1000) / bit_rate);
  if (fec_oc_dto_period <= 2)
   fec_oc_dto_period = 0;
  else
   fec_oc_dto_period -= 2;
  fec_oc_tmd_int_upd_rate = 8;
 } else {
  /* (commonAttr->static_clk == false) => dynamic mode */
  fec_oc_dto_mode = FEC_OC_DTO_MODE_DYNAMIC__M;
  fec_oc_fct_mode = FEC_OC_FCT_MODE__PRE;
  fec_oc_tmd_int_upd_rate = 5;
 }

 /* Write appropriate registers with requested configuration */
 status = write16(state, FEC_OC_DTO_BURST_LEN__A, fec_oc_dto_burst_len);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_DTO_PERIOD__A, fec_oc_dto_period);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_DTO_MODE__A, fec_oc_dto_mode);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_FCT_MODE__A, fec_oc_fct_mode);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_MODE__A, fec_oc_reg_mode);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_IPR_MODE__A, fec_oc_reg_ipr_mode);
 if (status < 0)
  goto error;

 /* Rate integration settings */
 status = write32(state, FEC_OC_RCN_CTL_RATE_LO__A, fec_oc_rcn_ctl_rate);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_TMD_INT_UPD_RATE__A,
    fec_oc_tmd_int_upd_rate);
 if (status < 0)
  goto error;
 status = write16(state, FEC_OC_TMD_MODE__A, fec_oc_tmd_mode);
error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);
 return status;
}

static int mpegts_configure_polarity(struct drxk_state *state)
{
 u16 fec_oc_reg_ipr_invert = 0;

 /* Data mask for the output data byte */
 u16 invert_data_mask =
     FEC_OC_IPR_INVERT_MD7__M | FEC_OC_IPR_INVERT_MD6__M |
     FEC_OC_IPR_INVERT_MD5__M | FEC_OC_IPR_INVERT_MD4__M |
     FEC_OC_IPR_INVERT_MD3__M | FEC_OC_IPR_INVERT_MD2__M |
     FEC_OC_IPR_INVERT_MD1__M | FEC_OC_IPR_INVERT_MD0__M;

 dprintk(1, "\n");

 /* Control selective inversion of output bits */
 fec_oc_reg_ipr_invert &= (~(invert_data_mask));
 if (state->m_invert_data)
  fec_oc_reg_ipr_invert |= invert_data_mask;
 fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MERR__M));
 if (state->m_invert_err)
  fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MERR__M;
 fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MSTRT__M));
 if (state->m_invert_str)
  fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MSTRT__M;
 fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MVAL__M));
 if (state->m_invert_val)
  fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MVAL__M;
 fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MCLK__M));
 if (state->m_invert_clk)
  fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MCLK__M;

 return write16(state, FEC_OC_IPR_INVERT__A, fec_oc_reg_ipr_invert);
}

#define   SCU_RAM_AGC_KI_INV_RF_POL__M 0x4000

static int set_agc_rf(struct drxk_state *state,
      struct s_cfg_agc *p_agc_cfg, bool is_dtv)
{
 int status = -EINVAL;
 u16 data = 0;
 struct s_cfg_agc *p_if_agc_settings;

 dprintk(1, "\n");

 if (p_agc_cfg == NULL)
  goto error;

 switch (p_agc_cfg->ctrl_mode) {
 case DRXK_AGC_CTRL_AUTO:
  /* Enable RF AGC DAC */
  status = read16(state, IQM_AF_STDBY__A, &data);
  if (status < 0)
   goto error;
  data &= ~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY;
  status = write16(state, IQM_AF_STDBY__A, data);
  if (status < 0)
   goto error;
  status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
  if (status < 0)
   goto error;

  /* Enable SCU RF AGC loop */
  data &= ~SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;

  /* Polarity */
  if (state->m_rf_agc_pol)
   data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
  else
   data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
  status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
  if (status < 0)
   goto error;

  /* Set speed (using complementary reduction value) */
  status = read16(state, SCU_RAM_AGC_KI_RED__A, &data);
  if (status < 0)
   goto error;

  data &= ~SCU_RAM_AGC_KI_RED_RAGC_RED__M;
  data |= (~(p_agc_cfg->speed <<
    SCU_RAM_AGC_KI_RED_RAGC_RED__B)
    & SCU_RAM_AGC_KI_RED_RAGC_RED__M);

  status = write16(state, SCU_RAM_AGC_KI_RED__A, data);
  if (status < 0)
   goto error;

  if (is_dvbt(state))
   p_if_agc_settings = &state->m_dvbt_if_agc_cfg;
  else if (is_qam(state))
   p_if_agc_settings = &state->m_qam_if_agc_cfg;
  else
   p_if_agc_settings = &state->m_atv_if_agc_cfg;
  if (p_if_agc_settings == NULL) {
   status = -EINVAL;
   goto error;
  }

  /* Set TOP, only if IF-AGC is in AUTO mode */
  if (p_if_agc_settings->ctrl_mode == DRXK_AGC_CTRL_AUTO) {
   status = write16(state,
      SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A,
      p_agc_cfg->top);
   if (status < 0)
    goto error;
  }

  /* Cut-Off current */
  status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A,
     p_agc_cfg->cut_off_current);
  if (status < 0)
   goto error;

  /* Max. output level */
  status = write16(state, SCU_RAM_AGC_RF_MAX__A,
     p_agc_cfg->max_output_level);
  if (status < 0)
   goto error;

  break;

 case DRXK_AGC_CTRL_USER:
  /* Enable RF AGC DAC */
  status = read16(state, IQM_AF_STDBY__A, &data);
  if (status < 0)
   goto error;
  data &= ~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY;
  status = write16(state, IQM_AF_STDBY__A, data);
  if (status < 0)
   goto error;

  /* Disable SCU RF AGC loop */
  status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
  if (status < 0)
   goto error;
  data |= SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
  if (state->m_rf_agc_pol)
   data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
  else
   data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
  status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
  if (status < 0)
   goto error;

  /* SCU c.o.c. to 0, enabling full control range */
  status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, 0);
  if (status < 0)
   goto error;

  /* Write value to output pin */
  status = write16(state, SCU_RAM_AGC_RF_IACCU_HI__A,
     p_agc_cfg->output_level);
  if (status < 0)
   goto error;
  break;

 case DRXK_AGC_CTRL_OFF:
  /* Disable RF AGC DAC */
  status = read16(state, IQM_AF_STDBY__A, &data);
  if (status < 0)
   goto error;
  data |= IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY;
  status = write16(state, IQM_AF_STDBY__A, data);
  if (status < 0)
   goto error;

  /* Disable SCU RF AGC loop */
  status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
  if (status < 0)
   goto error;
  data |= SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
  status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
  if (status < 0)
   goto error;
  break;

 default:
  status = -EINVAL;

 }
error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);
 return status;
}

#define SCU_RAM_AGC_KI_INV_IF_POL__M 0x2000

static int set_agc_if(struct drxk_state *state,
      struct s_cfg_agc *p_agc_cfg, bool is_dtv)
{
 u16 data = 0;
 int status = 0;
 struct s_cfg_agc *p_rf_agc_settings;

 dprintk(1, "\n");

 switch (p_agc_cfg->ctrl_mode) {
 case DRXK_AGC_CTRL_AUTO:

  /* Enable IF AGC DAC */
  status = read16(state, IQM_AF_STDBY__A, &data);
  if (status < 0)
   goto error;
  data &= ~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY;
  status = write16(state, IQM_AF_STDBY__A, data);
  if (status < 0)
   goto error;

  status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
  if (status < 0)
   goto error;

  /* Enable SCU IF AGC loop */
  data &= ~SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;

  /* Polarity */
  if (state->m_if_agc_pol)
   data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
  else
   data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
  status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
  if (status < 0)
   goto error;

  /* Set speed (using complementary reduction value) */
  status = read16(state, SCU_RAM_AGC_KI_RED__A, &data);
  if (status < 0)
   goto error;
  data &= ~SCU_RAM_AGC_KI_RED_IAGC_RED__M;
  data |= (~(p_agc_cfg->speed <<
    SCU_RAM_AGC_KI_RED_IAGC_RED__B)
    & SCU_RAM_AGC_KI_RED_IAGC_RED__M);

  status = write16(state, SCU_RAM_AGC_KI_RED__A, data);
  if (status < 0)
   goto error;

  if (is_qam(state))
   p_rf_agc_settings = &state->m_qam_rf_agc_cfg;
  else
   p_rf_agc_settings = &state->m_atv_rf_agc_cfg;
  if (p_rf_agc_settings == NULL)
   return -1;
  /* Restore TOP */
  status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A,
     p_rf_agc_settings->top);
  if (status < 0)
   goto error;
  break;

 case DRXK_AGC_CTRL_USER:

  /* Enable IF AGC DAC */
  status = read16(state, IQM_AF_STDBY__A, &data);
  if (status < 0)
   goto error;
  data &= ~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY;
  status = write16(state, IQM_AF_STDBY__A, data);
  if (status < 0)
   goto error;

  status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
  if (status < 0)
   goto error;

  /* Disable SCU IF AGC loop */
  data |= SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;

  /* Polarity */
  if (state->m_if_agc_pol)
   data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
  else
   data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
  status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
  if (status < 0)
   goto error;

  /* Write value to output pin */
  status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A,
     p_agc_cfg->output_level);
  if (status < 0)
   goto error;
  break;

 case DRXK_AGC_CTRL_OFF:

  /* Disable If AGC DAC */
  status = read16(state, IQM_AF_STDBY__A, &data);
  if (status < 0)
   goto error;
  data |= IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY;
  status = write16(state, IQM_AF_STDBY__A, data);
  if (status < 0)
   goto error;

  /* Disable SCU IF AGC loop */
  status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
  if (status < 0)
   goto error;
  data |= SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
  status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
  if (status < 0)
   goto error;
  break;
 }  /* switch (agcSettingsIf->ctrl_mode) */

 /* always set the top to support
configurations without if-loop */

 status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, p_agc_cfg->top);
error:
 if (status < 0)
  pr_err("Error %d on %s\n", status, __func__);
 return status;
}

static int get_qam_signal_to_noise(struct drxk_state *state,
          s32 *p_signal_to_noise)
{
 int status = 0;
 u16 qam_sl_err_power = 0; /* accum. error between
raw and sliced symbols */

 u32 qam_sl_sig_power = 0; /* used for MER, depends of
QAM modulation */

 u32 qam_sl_mer = 0; /* QAM MER */

 dprintk(1, "\n");

 /* MER calculation */

 /* get the register value needed for MER */
 status = read16(state, QAM_SL_ERR_POWER__A, &qam_sl_err_power);
 if (status < 0) {
  pr_err("Error %d on %s\n", status, __func__);
  return -EINVAL;
 }

 switch (state->props.modulation) {
 case QAM_16:
  qam_sl_sig_power = DRXK_QAM_SL_SIG_POWER_QAM16 << 2;
  break;
 case QAM_32:
  qam_sl_sig_power = DRXK_QAM_SL_SIG_POWER_QAM32 << 2;
  break;
 case QAM_64:
  qam_sl_sig_power = DRXK_QAM_SL_SIG_POWER_QAM64 << 2;
  break;
 case QAM_128:
  qam_sl_sig_power = DRXK_QAM_SL_SIG_POWER_QAM128 << 2;
  break;
 default:
 case QAM_256:
  qam_sl_sig_power = DRXK_QAM_SL_SIG_POWER_QAM256 << 2;
  break;
 }

 if (qam_sl_err_power > 0) {
  qam_sl_mer = log10times100(qam_sl_sig_power) -
   log10times100((u32) qam_sl_err_power);
 }
 *p_signal_to_noise = qam_sl_mer;

 return status;
}

static int get_dvbt_signal_to_noise(struct drxk_state *state,
    s32 *p_signal_to_noise)
{
 int status;
 u16 reg_data = 0;
 u32 eq_reg_td_sqr_err_i = 0;
 u32 eq_reg_td_sqr_err_q = 0;
 u16 eq_reg_td_sqr_err_exp = 0;
 u16 eq_reg_td_tps_pwr_ofs = 0;
 u16 eq_reg_td_req_smb_cnt = 0;
 u32 tps_cnt = 0;
 u32 sqr_err_iq = 0;
 u32 a = 0;
 u32 b = 0;
 u32 c = 0;
 u32 i_mer = 0;
 u16 transmission_params = 0;

 dprintk(1, "\n");

 status = read16(state, OFDM_EQ_TOP_TD_TPS_PWR_OFS__A,
   &eq_reg_td_tps_pwr_ofs);
 if (status < 0)
  goto error;
 status = read16(state, OFDM_EQ_TOP_TD_REQ_SMB_CNT__A,
   &eq_reg_td_req_smb_cnt);
 if (status < 0)
  goto error;
 status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_EXP__A,
   &eq_reg_td_sqr_err_exp);
 if (status < 0)
  goto error;
 status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_I__A,
   ®_data);
 if (status < 0)
  goto error;
 /* Extend SQR_ERR_I operational range */
 eq_reg_td_sqr_err_i = (u32) reg_data;
 if ((eq_reg_td_sqr_err_exp > 11) &&
  (eq_reg_td_sqr_err_i < 0x00000FFFUL)) {
  eq_reg_td_sqr_err_i += 0x00010000UL;
 }
 status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_Q__A, ®_data);
 if (status < 0)
  goto error;
 /* Extend SQR_ERR_Q operational range */
--> --------------------

--> maximum size reached

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

Messung V0.5
C=94 H=82 G=88

¤ Dauer der Verarbeitung: 0.22 Sekunden  ¤

*© 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.