]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
media: dvb-frontends: MaxLinear MxL5xx DVB-S/S2 tuner-demodulator driver
authorDaniel Scheller <d.scheller@gmx.net>
Sun, 9 Jul 2017 19:42:43 +0000 (15:42 -0400)
committerMauro Carvalho Chehab <mchehab@s-opensource.com>
Sun, 20 Aug 2017 11:25:09 +0000 (07:25 -0400)
This adds the frontend driver for the MaxLinear MxL5xx family of tuner-
demodulators, as used on Digital Devices MaxS4/8 four/eight-tuner cards.

The driver was picked from the dddvb vendor driver package and - judging
solely from the diff - has undergone a 100% rework:

 - Silly #define's used to pass multiple values to functions were
   expanded. This resulted in macro/register names not being usable
   anymore for such occurences, but makes the code WAY more read-,
   understand- and maintainable.
 - CamelCase was changed to kernel_case
 - All typedef were removed
 - Overall code style was fixed, besides >80char lines in _defs.h and
   _regs.h, checkpatch is happy.
 - Also, signal stat acquisition was made to comply with the DVB API
   ways to do these things.

Permission to reuse and mainline the driver code was formally granted by
Ralph Metzler <rjkm@metzlerbros.de>.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
drivers/media/dvb-frontends/Kconfig
drivers/media/dvb-frontends/Makefile
drivers/media/dvb-frontends/mxl5xx.c [new file with mode: 0644]
drivers/media/dvb-frontends/mxl5xx.h [new file with mode: 0644]
drivers/media/dvb-frontends/mxl5xx_defs.h [new file with mode: 0644]
drivers/media/dvb-frontends/mxl5xx_regs.h [new file with mode: 0644]

index d2d3160abdf7ce65427ee00c4313061cc9a92303..2631d0e0a024d4989d8ff14e3fc91f714753f756 100644 (file)
@@ -53,6 +53,15 @@ config DVB_STV6111
 
          Say Y when you want to support these frontends.
 
+config DVB_MXL5XX
+       tristate "MaxLinear MxL5xx based tuner-demodulators"
+       depends on DVB_CORE && I2C
+       default m if !MEDIA_SUBDRV_AUTOSELECT
+       help
+         MaxLinear MxL5xx family of DVB-S/S2 tuners/demodulators.
+
+         Say Y when you want to support these frontends.
+
 config DVB_M88DS3103
        tristate "Montage Technology M88DS3103"
        depends on DVB_CORE && I2C && I2C_MUX
index e8bf1d8734852bd85686980ea4e77ff30c593b44..f45f6a4a437142226399142e0667850e214719d6 100644 (file)
@@ -112,6 +112,7 @@ obj-$(CONFIG_DVB_DRXK) += drxk.o
 obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
 obj-$(CONFIG_DVB_STV0910) += stv0910.o
 obj-$(CONFIG_DVB_STV6111) += stv6111.o
+obj-$(CONFIG_DVB_MXL5XX) += mxl5xx.o
 obj-$(CONFIG_DVB_SI2165) += si2165.o
 obj-$(CONFIG_DVB_A8293) += a8293.o
 obj-$(CONFIG_DVB_SP2) += sp2.o
diff --git a/drivers/media/dvb-frontends/mxl5xx.c b/drivers/media/dvb-frontends/mxl5xx.c
new file mode 100644 (file)
index 0000000..676c96c
--- /dev/null
@@ -0,0 +1,1873 @@
+/*
+ * Driver for the MaxLinear MxL5xx family of tuners/demods
+ *
+ * Copyright (C) 2014-2015 Ralph Metzler <rjkm@metzlerbros.de>
+ *                         Marcus Metzler <mocm@metzlerbros.de>
+ *                         developed for Digital Devices GmbH
+ *
+ * based on code:
+ * Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved
+ * which was released under GPL V2
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#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/version.h>
+#include <linux/mutex.h>
+#include <linux/vmalloc.h>
+#include <asm/div64.h>
+#include <asm/unaligned.h>
+
+#include "dvb_frontend.h"
+#include "mxl5xx.h"
+#include "mxl5xx_regs.h"
+#include "mxl5xx_defs.h"
+
+#define BYTE0(v) ((v >>  0) & 0xff)
+#define BYTE1(v) ((v >>  8) & 0xff)
+#define BYTE2(v) ((v >> 16) & 0xff)
+#define BYTE3(v) ((v >> 24) & 0xff)
+
+LIST_HEAD(mxllist);
+
+struct mxl_base {
+       struct list_head     mxllist;
+       struct list_head     mxls;
+
+       u8                   adr;
+       struct i2c_adapter  *i2c;
+
+       u32                  count;
+       u32                  type;
+       u32                  sku_type;
+       u32                  chipversion;
+       u32                  clock;
+       u32                  fwversion;
+
+       u8                  *ts_map;
+       u8                   can_clkout;
+       u8                   chan_bond;
+       u8                   demod_num;
+       u8                   tuner_num;
+
+       unsigned long        next_tune;
+
+       struct mutex         i2c_lock;
+       struct mutex         status_lock;
+       struct mutex         tune_lock;
+
+       u8                   buf[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN];
+
+       u32                  cmd_size;
+       u8                   cmd_data[MAX_CMD_DATA];
+};
+
+struct mxl {
+       struct list_head     mxl;
+
+       struct mxl_base     *base;
+       struct dvb_frontend  fe;
+       struct device       *i2cdev;
+       u32                  demod;
+       u32                  tuner;
+       u32                  tuner_in_use;
+       u8                   xbar[3];
+
+       unsigned long        tune_time;
+};
+
+static void convert_endian(u8 flag, u32 size, u8 *d)
+{
+       u32 i;
+
+       if (!flag)
+               return;
+       for (i = 0; i < (size & ~3); i += 4) {
+               d[i + 0] ^= d[i + 3];
+               d[i + 3] ^= d[i + 0];
+               d[i + 0] ^= d[i + 3];
+
+               d[i + 1] ^= d[i + 2];
+               d[i + 2] ^= d[i + 1];
+               d[i + 1] ^= d[i + 2];
+       }
+
+       switch (size & 3) {
+       case 0:
+       case 1:
+               /* do nothing */
+               break;
+       case 2:
+               d[i + 0] ^= d[i + 1];
+               d[i + 1] ^= d[i + 0];
+               d[i + 0] ^= d[i + 1];
+               break;
+
+       case 3:
+               d[i + 0] ^= d[i + 2];
+               d[i + 2] ^= d[i + 0];
+               d[i + 0] ^= d[i + 2];
+               break;
+       }
+
+}
+
+static int i2c_write(struct i2c_adapter *adap, u8 adr,
+                           u8 *data, u32 len)
+{
+       struct i2c_msg msg = {.addr = adr, .flags = 0,
+                             .buf = data, .len = len};
+
+       return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1;
+}
+
+static int i2c_read(struct i2c_adapter *adap, u8 adr,
+                          u8 *data, u32 len)
+{
+       struct i2c_msg msg = {.addr = adr, .flags = I2C_M_RD,
+                             .buf = data, .len = len};
+
+       return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1;
+}
+
+static int i2cread(struct mxl *state, u8 *data, int len)
+{
+       return i2c_read(state->base->i2c, state->base->adr, data, len);
+}
+
+static int i2cwrite(struct mxl *state, u8 *data, int len)
+{
+       return i2c_write(state->base->i2c, state->base->adr, data, len);
+}
+
+static int read_register_unlocked(struct mxl *state, u32 reg, u32 *val)
+{
+       int stat;
+       u8 data[MXL_HYDRA_REG_SIZE_IN_BYTES + MXL_HYDRA_I2C_HDR_SIZE] = {
+               MXL_HYDRA_PLID_REG_READ, 0x04,
+               GET_BYTE(reg, 0), GET_BYTE(reg, 1),
+               GET_BYTE(reg, 2), GET_BYTE(reg, 3),
+       };
+
+       stat = i2cwrite(state, data,
+                       MXL_HYDRA_REG_SIZE_IN_BYTES + MXL_HYDRA_I2C_HDR_SIZE);
+       if (stat)
+               dev_err(state->i2cdev, "i2c read error 1\n");
+       if (!stat)
+               stat = i2cread(state, (u8 *) val,
+                              MXL_HYDRA_REG_SIZE_IN_BYTES);
+       le32_to_cpus(val);
+       if (stat)
+               dev_err(state->i2cdev, "i2c read error 2\n");
+       return stat;
+}
+
+#define DMA_I2C_INTERRUPT_ADDR 0x8000011C
+#define DMA_INTR_PROT_WR_CMP 0x08
+
+static int send_command(struct mxl *state, u32 size, u8 *buf)
+{
+       int stat;
+       u32 val, count = 10;
+
+       mutex_lock(&state->base->i2c_lock);
+       if (state->base->fwversion > 0x02010109)  {
+               read_register_unlocked(state, DMA_I2C_INTERRUPT_ADDR, &val);
+               if (DMA_INTR_PROT_WR_CMP & val)
+                       dev_info(state->i2cdev, "%s busy\n", __func__);
+               while ((DMA_INTR_PROT_WR_CMP & val) && --count) {
+                       mutex_unlock(&state->base->i2c_lock);
+                       usleep_range(1000, 2000);
+                       mutex_lock(&state->base->i2c_lock);
+                       read_register_unlocked(state, DMA_I2C_INTERRUPT_ADDR,
+                                              &val);
+               }
+               if (!count) {
+                       dev_info(state->i2cdev, "%s busy\n", __func__);
+                       mutex_unlock(&state->base->i2c_lock);
+                       return -EBUSY;
+               }
+       }
+       stat = i2cwrite(state, buf, size);
+       mutex_unlock(&state->base->i2c_lock);
+       return stat;
+}
+
+static int write_register(struct mxl *state, u32 reg, u32 val)
+{
+       int stat;
+       u8 data[MXL_HYDRA_REG_WRITE_LEN] = {
+               MXL_HYDRA_PLID_REG_WRITE, 0x08,
+               BYTE0(reg), BYTE1(reg), BYTE2(reg), BYTE3(reg),
+               BYTE0(val), BYTE1(val), BYTE2(val), BYTE3(val),
+       };
+       mutex_lock(&state->base->i2c_lock);
+       stat = i2cwrite(state, data, sizeof(data));
+       mutex_unlock(&state->base->i2c_lock);
+       if (stat)
+               dev_err(state->i2cdev, "i2c write error\n");
+       return stat;
+}
+
+static int write_firmware_block(struct mxl *state,
+                               u32 reg, u32 size, u8 *reg_data_ptr)
+{
+       int stat;
+       u8 *buf = state->base->buf;
+
+       mutex_lock(&state->base->i2c_lock);
+       buf[0] = MXL_HYDRA_PLID_REG_WRITE;
+       buf[1] = size + 4;
+       buf[2] = GET_BYTE(reg, 0);
+       buf[3] = GET_BYTE(reg, 1);
+       buf[4] = GET_BYTE(reg, 2);
+       buf[5] = GET_BYTE(reg, 3);
+       memcpy(&buf[6], reg_data_ptr, size);
+       stat = i2cwrite(state, buf,
+                       MXL_HYDRA_I2C_HDR_SIZE +
+                       MXL_HYDRA_REG_SIZE_IN_BYTES + size);
+       mutex_unlock(&state->base->i2c_lock);
+       if (stat)
+               dev_err(state->i2cdev, "fw block write failed\n");
+       return stat;
+}
+
+static int read_register(struct mxl *state, u32 reg, u32 *val)
+{
+       int stat;
+       u8 data[MXL_HYDRA_REG_SIZE_IN_BYTES + MXL_HYDRA_I2C_HDR_SIZE] = {
+               MXL_HYDRA_PLID_REG_READ, 0x04,
+               GET_BYTE(reg, 0), GET_BYTE(reg, 1),
+               GET_BYTE(reg, 2), GET_BYTE(reg, 3),
+       };
+
+       mutex_lock(&state->base->i2c_lock);
+       stat = i2cwrite(state, data,
+                       MXL_HYDRA_REG_SIZE_IN_BYTES + MXL_HYDRA_I2C_HDR_SIZE);
+       if (stat)
+               dev_err(state->i2cdev, "i2c read error 1\n");
+       if (!stat)
+               stat = i2cread(state, (u8 *) val,
+                              MXL_HYDRA_REG_SIZE_IN_BYTES);
+       mutex_unlock(&state->base->i2c_lock);
+       le32_to_cpus(val);
+       if (stat)
+               dev_err(state->i2cdev, "i2c read error 2\n");
+       return stat;
+}
+
+static int read_register_block(struct mxl *state, u32 reg, u32 size, u8 *data)
+{
+       int stat;
+       u8 *buf = state->base->buf;
+
+       mutex_lock(&state->base->i2c_lock);
+
+       buf[0] = MXL_HYDRA_PLID_REG_READ;
+       buf[1] = size + 4;
+       buf[2] = GET_BYTE(reg, 0);
+       buf[3] = GET_BYTE(reg, 1);
+       buf[4] = GET_BYTE(reg, 2);
+       buf[5] = GET_BYTE(reg, 3);
+       stat = i2cwrite(state, buf,
+                       MXL_HYDRA_I2C_HDR_SIZE + MXL_HYDRA_REG_SIZE_IN_BYTES);
+       if (!stat) {
+               stat = i2cread(state, data, size);
+               convert_endian(MXL_ENABLE_BIG_ENDIAN, size, data);
+       }
+       mutex_unlock(&state->base->i2c_lock);
+       return stat;
+}
+
+static int read_by_mnemonic(struct mxl *state,
+                           u32 reg, u8 lsbloc, u8 numofbits, u32 *val)
+{
+       u32 data = 0, mask = 0;
+       int stat;
+
+       stat = read_register(state, reg, &data);
+       if (stat)
+               return stat;
+       mask = MXL_GET_REG_MASK_32(lsbloc, numofbits);
+       data &= mask;
+       data >>= lsbloc;
+       *val = data;
+       return 0;
+}
+
+
+static int update_by_mnemonic(struct mxl *state,
+                             u32 reg, u8 lsbloc, u8 numofbits, u32 val)
+{
+       u32 data, mask;
+       int stat;
+
+       stat = read_register(state, reg, &data);
+       if (stat)
+               return stat;
+       mask = MXL_GET_REG_MASK_32(lsbloc, numofbits);
+       data = (data & ~mask) | ((val << lsbloc) & mask);
+       stat = write_register(state, reg, data);
+       return stat;
+}
+
+static int firmware_is_alive(struct mxl *state)
+{
+       u32 hb0, hb1;
+
+       if (read_register(state, HYDRA_HEAR_BEAT, &hb0))
+               return 0;
+       msleep(20);
+       if (read_register(state, HYDRA_HEAR_BEAT, &hb1))
+               return 0;
+       if (hb1 == hb0)
+               return 0;
+       return 1;
+}
+
+static int init(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+       /* init fe stats */
+       p->strength.len = 1;
+       p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       p->cnr.len = 1;
+       p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       p->pre_bit_error.len = 1;
+       p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       p->pre_bit_count.len = 1;
+       p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       p->post_bit_error.len = 1;
+       p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       p->post_bit_count.len = 1;
+       p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+       return 0;
+}
+
+static void release(struct dvb_frontend *fe)
+{
+       struct mxl *state = fe->demodulator_priv;
+
+       list_del(&state->mxl);
+       /* Release one frontend, two more shall take its place! */
+       state->base->count--;
+       if (state->base->count == 0) {
+               list_del(&state->base->mxllist);
+               kfree(state->base);
+       }
+       kfree(state);
+}
+
+static int get_algo(struct dvb_frontend *fe)
+{
+       return DVBFE_ALGO_HW;
+}
+
+static int cfg_demod_abort_tune(struct mxl *state)
+{
+       struct MXL_HYDRA_DEMOD_ABORT_TUNE_T abort_tune_cmd;
+       u8 cmd_size = sizeof(abort_tune_cmd);
+       u8 cmd_buff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN];
+
+       abort_tune_cmd.demod_id = state->demod;
+       BUILD_HYDRA_CMD(MXL_HYDRA_ABORT_TUNE_CMD, MXL_CMD_WRITE,
+                       cmd_size, &abort_tune_cmd, cmd_buff);
+       return send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE,
+                           &cmd_buff[0]);
+}
+
+static int send_master_cmd(struct dvb_frontend *fe,
+                          struct dvb_diseqc_master_cmd *cmd)
+{
+       /*struct mxl *state = fe->demodulator_priv;*/
+
+       return 0; /*CfgDemodAbortTune(state);*/
+}
+
+static int set_parameters(struct dvb_frontend *fe)
+{
+       struct mxl *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+       struct MXL_HYDRA_DEMOD_PARAM_T demod_chan_cfg;
+       u8 cmd_size = sizeof(demod_chan_cfg);
+       u8 cmd_buff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN];
+       u32 srange = 10;
+       int stat;
+
+       if (p->frequency < 950000 || p->frequency > 2150000)
+               return -EINVAL;
+       if (p->symbol_rate < 1000000 || p->symbol_rate > 45000000)
+               return -EINVAL;
+
+       /* CfgDemodAbortTune(state); */
+
+       switch (p->delivery_system) {
+       case SYS_DSS:
+               demod_chan_cfg.standard = MXL_HYDRA_DSS;
+               demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_AUTO;
+               break;
+       case SYS_DVBS:
+               srange = p->symbol_rate / 1000000;
+               if (srange > 10)
+                       srange = 10;
+               demod_chan_cfg.standard = MXL_HYDRA_DVBS;
+               demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_0_35;
+               demod_chan_cfg.modulation_scheme = MXL_HYDRA_MOD_QPSK;
+               demod_chan_cfg.pilots = MXL_HYDRA_PILOTS_OFF;
+               break;
+       case SYS_DVBS2:
+               demod_chan_cfg.standard = MXL_HYDRA_DVBS2;
+               demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_AUTO;
+               demod_chan_cfg.modulation_scheme = MXL_HYDRA_MOD_AUTO;
+               demod_chan_cfg.pilots = MXL_HYDRA_PILOTS_AUTO;
+               /* cfg_scrambler(state); */
+               break;
+       default:
+               return -EINVAL;
+       }
+       demod_chan_cfg.tuner_index = state->tuner;
+       demod_chan_cfg.demod_index = state->demod;
+       demod_chan_cfg.frequency_in_hz = p->frequency * 1000;
+       demod_chan_cfg.symbol_rate_in_hz = p->symbol_rate;
+       demod_chan_cfg.max_carrier_offset_in_mhz = srange;
+       demod_chan_cfg.spectrum_inversion = MXL_HYDRA_SPECTRUM_AUTO;
+       demod_chan_cfg.fec_code_rate = MXL_HYDRA_FEC_AUTO;
+
+       mutex_lock(&state->base->tune_lock);
+       if (time_after(jiffies + msecs_to_jiffies(200),
+                      state->base->next_tune))
+               while (time_before(jiffies, state->base->next_tune))
+                       usleep_range(10000, 11000);
+       state->base->next_tune = jiffies + msecs_to_jiffies(100);
+       state->tuner_in_use = state->tuner;
+       BUILD_HYDRA_CMD(MXL_HYDRA_DEMOD_SET_PARAM_CMD, MXL_CMD_WRITE,
+                       cmd_size, &demod_chan_cfg, cmd_buff);
+       stat = send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE,
+                           &cmd_buff[0]);
+       mutex_unlock(&state->base->tune_lock);
+       return stat;
+}
+
+static int enable_tuner(struct mxl *state, u32 tuner, u32 enable);
+
+static int sleep(struct dvb_frontend *fe)
+{
+       struct mxl *state = fe->demodulator_priv;
+       struct mxl *p;
+
+       cfg_demod_abort_tune(state);
+       if (state->tuner_in_use != 0xffffffff) {
+               mutex_lock(&state->base->tune_lock);
+               state->tuner_in_use = 0xffffffff;
+               list_for_each_entry(p, &state->base->mxls, mxl) {
+                       if (p->tuner_in_use == state->tuner)
+                               break;
+               }
+               if (&p->mxl == &state->base->mxls)
+                       enable_tuner(state, state->tuner, 0);
+               mutex_unlock(&state->base->tune_lock);
+       }
+       return 0;
+}
+
+static int read_snr(struct dvb_frontend *fe)
+{
+       struct mxl *state = fe->demodulator_priv;
+       int stat;
+       u32 reg_data = 0;
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+       mutex_lock(&state->base->status_lock);
+       HYDRA_DEMOD_STATUS_LOCK(state, state->demod);
+       stat = read_register(state, (HYDRA_DMD_SNR_ADDR_OFFSET +
+                                    HYDRA_DMD_STATUS_OFFSET(state->demod)),
+                            &reg_data);
+       HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod);
+       mutex_unlock(&state->base->status_lock);
+
+       p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+       p->cnr.stat[0].svalue = (s16)reg_data * 10;
+
+       return stat;
+}
+
+static int read_ber(struct dvb_frontend *fe)
+{
+       struct mxl *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+       u32 reg[8];
+
+       mutex_lock(&state->base->status_lock);
+       HYDRA_DEMOD_STATUS_LOCK(state, state->demod);
+       read_register_block(state,
+               (HYDRA_DMD_DVBS_1ST_CORR_RS_ERRORS_ADDR_OFFSET +
+                HYDRA_DMD_STATUS_OFFSET(state->demod)),
+               (4 * sizeof(u32)),
+               (u8 *) &reg[0]);
+       HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod);
+
+       switch (p->delivery_system) {
+       case SYS_DSS:
+       case SYS_DVBS:
+               p->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+               p->pre_bit_error.stat[0].uvalue = reg[2];
+               p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+               p->pre_bit_count.stat[0].uvalue = reg[3];
+               break;
+       default:
+               break;
+       }
+
+       read_register_block(state,
+               (HYDRA_DMD_DVBS2_CRC_ERRORS_ADDR_OFFSET +
+                HYDRA_DMD_STATUS_OFFSET(state->demod)),
+               (7 * sizeof(u32)),
+               (u8 *) &reg[0]);
+
+       switch (p->delivery_system) {
+       case SYS_DSS:
+       case SYS_DVBS:
+               p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+               p->post_bit_error.stat[0].uvalue = reg[5];
+               p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+               p->post_bit_count.stat[0].uvalue = reg[6];
+               break;
+       case SYS_DVBS2:
+               p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+               p->post_bit_error.stat[0].uvalue = reg[1];
+               p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+               p->post_bit_count.stat[0].uvalue = reg[2];
+               break;
+       default:
+               break;
+       }
+
+       mutex_unlock(&state->base->status_lock);
+
+       return 0;
+}
+
+static int read_signal_strength(struct dvb_frontend *fe)
+{
+       struct mxl *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+       int stat;
+       u32 reg_data = 0;
+
+       mutex_lock(&state->base->status_lock);
+       HYDRA_DEMOD_STATUS_LOCK(state, state->demod);
+       stat = read_register(state, (HYDRA_DMD_STATUS_INPUT_POWER_ADDR +
+                                    HYDRA_DMD_STATUS_OFFSET(state->demod)),
+                            &reg_data);
+       HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod);
+       mutex_unlock(&state->base->status_lock);
+
+       p->strength.stat[0].scale = FE_SCALE_DECIBEL;
+       p->strength.stat[0].svalue = (s16) reg_data * 10; /* fix scale */
+
+       return stat;
+}
+
+static int read_status(struct dvb_frontend *fe, enum fe_status *status)
+{
+       struct mxl *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+       u32 reg_data = 0;
+
+       mutex_lock(&state->base->status_lock);
+       HYDRA_DEMOD_STATUS_LOCK(state, state->demod);
+       read_register(state, (HYDRA_DMD_LOCK_STATUS_ADDR_OFFSET +
+                            HYDRA_DMD_STATUS_OFFSET(state->demod)),
+                            &reg_data);
+       HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod);
+       mutex_unlock(&state->base->status_lock);
+
+       *status = (reg_data == 1) ? 0x1f : 0;
+
+       /* signal statistics */
+
+       /* signal strength is always available */
+       read_signal_strength(fe);
+
+       if (*status & FE_HAS_CARRIER)
+               read_snr(fe);
+       else
+               p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+       if (*status & FE_HAS_SYNC)
+               read_ber(fe);
+       else {
+               p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+               p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+               p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+               p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       }
+
+       return 0;
+}
+
+static int tune(struct dvb_frontend *fe, bool re_tune,
+               unsigned int mode_flags,
+               unsigned int *delay, enum fe_status *status)
+{
+       struct mxl *state = fe->demodulator_priv;
+       int r = 0;
+
+       *delay = HZ / 2;
+       if (re_tune) {
+               r = set_parameters(fe);
+               if (r)
+                       return r;
+               state->tune_time = jiffies;
+               return 0;
+       }
+       if (*status & FE_HAS_LOCK)
+               return 0;
+
+       r = read_status(fe, status);
+       if (r)
+               return r;
+
+       return 0;
+}
+
+static enum fe_code_rate conv_fec(enum MXL_HYDRA_FEC_E fec)
+{
+       enum fe_code_rate fec2fec[11] = {
+               FEC_NONE, FEC_1_2, FEC_3_5, FEC_2_3,
+               FEC_3_4, FEC_4_5, FEC_5_6, FEC_6_7,
+               FEC_7_8, FEC_8_9, FEC_9_10
+       };
+
+       if (fec > MXL_HYDRA_FEC_9_10)
+               return FEC_NONE;
+       return fec2fec[fec];
+}
+
+static int get_frontend(struct dvb_frontend *fe,
+                       struct dtv_frontend_properties *p)
+{
+       struct mxl *state = fe->demodulator_priv;
+       u32 reg_data[MXL_DEMOD_CHAN_PARAMS_BUFF_SIZE];
+       u32 freq;
+
+       mutex_lock(&state->base->status_lock);
+       HYDRA_DEMOD_STATUS_LOCK(state, state->demod);
+       read_register_block(state,
+               (HYDRA_DMD_STANDARD_ADDR_OFFSET +
+               HYDRA_DMD_STATUS_OFFSET(state->demod)),
+               (MXL_DEMOD_CHAN_PARAMS_BUFF_SIZE * 4), /* 25 * 4 bytes */
+               (u8 *) &reg_data[0]);
+       /* read demod channel parameters */
+       read_register_block(state,
+               (HYDRA_DMD_STATUS_CENTER_FREQ_IN_KHZ_ADDR +
+               HYDRA_DMD_STATUS_OFFSET(state->demod)),
+               (4), /* 4 bytes */
+               (u8 *) &freq);
+       HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod);
+       mutex_unlock(&state->base->status_lock);
+
+       dev_dbg(state->i2cdev, "freq=%u delsys=%u srate=%u\n",
+               freq * 1000, reg_data[DMD_STANDARD_ADDR],
+               reg_data[DMD_SYMBOL_RATE_ADDR]);
+       p->symbol_rate = reg_data[DMD_SYMBOL_RATE_ADDR];
+       p->frequency = freq;
+       /*
+        * p->delivery_system =
+        *      (MXL_HYDRA_BCAST_STD_E) regData[DMD_STANDARD_ADDR];
+        * p->inversion =
+        *      (MXL_HYDRA_SPECTRUM_E) regData[DMD_SPECTRUM_INVERSION_ADDR];
+        * freqSearchRangeKHz =
+        *      (regData[DMD_FREQ_SEARCH_RANGE_IN_KHZ_ADDR]);
+        */
+
+       p->fec_inner = conv_fec(reg_data[DMD_FEC_CODE_RATE_ADDR]);
+       switch (p->delivery_system) {
+       case SYS_DSS:
+               break;
+       case SYS_DVBS2:
+               switch ((enum MXL_HYDRA_PILOTS_E)
+                       reg_data[DMD_DVBS2_PILOT_ON_OFF_ADDR]) {
+               case MXL_HYDRA_PILOTS_OFF:
+                       p->pilot = PILOT_OFF;
+                       break;
+               case MXL_HYDRA_PILOTS_ON:
+                       p->pilot = PILOT_ON;
+                       break;
+               default:
+                       break;
+               }
+       case SYS_DVBS:
+               switch ((enum MXL_HYDRA_MODULATION_E)
+                       reg_data[DMD_MODULATION_SCHEME_ADDR]) {
+               case MXL_HYDRA_MOD_QPSK:
+                       p->modulation = QPSK;
+                       break;
+               case MXL_HYDRA_MOD_8PSK:
+                       p->modulation = PSK_8;
+                       break;
+               default:
+                       break;
+               }
+               switch ((enum MXL_HYDRA_ROLLOFF_E)
+                       reg_data[DMD_SPECTRUM_ROLL_OFF_ADDR]) {
+               case MXL_HYDRA_ROLLOFF_0_20:
+                       p->rolloff = ROLLOFF_20;
+                       break;
+               case MXL_HYDRA_ROLLOFF_0_35:
+                       p->rolloff = ROLLOFF_35;
+                       break;
+               case MXL_HYDRA_ROLLOFF_0_25:
+                       p->rolloff = ROLLOFF_25;
+                       break;
+               default:
+                       break;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int set_input(struct dvb_frontend *fe, int input)
+{
+       struct mxl *state = fe->demodulator_priv;
+
+       state->tuner = input;
+       return 0;
+}
+
+static struct dvb_frontend_ops mxl_ops = {
+       .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
+       .info = {
+               .name                   = "MaxLinear MxL5xx DVB-S/S2 tuner-demodulator",
+               .frequency_min          = 300000,
+               .frequency_max          = 2350000,
+               .frequency_stepsize     = 0,
+               .frequency_tolerance    = 0,
+               .symbol_rate_min        = 1000000,
+               .symbol_rate_max        = 45000000,
+               .caps                   = FE_CAN_INVERSION_AUTO |
+                                         FE_CAN_FEC_AUTO       |
+                                         FE_CAN_QPSK           |
+                                         FE_CAN_2G_MODULATION
+       },
+       .init                           = init,
+       .release                        = release,
+       .get_frontend_algo              = get_algo,
+       .tune                           = tune,
+       .read_status                    = read_status,
+       .sleep                          = sleep,
+       .get_frontend                   = get_frontend,
+       .diseqc_send_master_cmd         = send_master_cmd,
+};
+
+static struct mxl_base *match_base(struct i2c_adapter  *i2c, u8 adr)
+{
+       struct mxl_base *p;
+
+       list_for_each_entry(p, &mxllist, mxllist)
+               if (p->i2c == i2c && p->adr == adr)
+                       return p;
+       return NULL;
+}
+
+static void cfg_dev_xtal(struct mxl *state, u32 freq, u32 cap, u32 enable)
+{
+       if (state->base->can_clkout || !enable)
+               update_by_mnemonic(state, 0x90200054, 23, 1, enable);
+
+       if (freq == 24000000)
+               write_register(state, HYDRA_CRYSTAL_SETTING, 0);
+       else
+               write_register(state, HYDRA_CRYSTAL_SETTING, 1);
+
+       write_register(state, HYDRA_CRYSTAL_CAP, cap);
+}
+
+static u32 get_big_endian(u8 num_of_bits, const u8 buf[])
+{
+       u32 ret_value = 0;
+
+       switch (num_of_bits) {
+       case 24:
+               ret_value = (((u32) buf[0]) << 16) |
+                       (((u32) buf[1]) << 8) | buf[2];
+               break;
+       case 32:
+               ret_value = (((u32) buf[0]) << 24) |
+                       (((u32) buf[1]) << 16) |
+                       (((u32) buf[2]) << 8) | buf[3];
+               break;
+       default:
+               break;
+       }
+
+       return ret_value;
+}
+
+static int write_fw_segment(struct mxl *state,
+                           u32 mem_addr, u32 total_size, u8 *data_ptr)
+{
+       int status;
+       u32 data_count = 0;
+       u32 size = 0;
+       u32 orig_size = 0;
+       u8 *w_buf_ptr = NULL;
+       u32 block_size = ((MXL_HYDRA_OEM_MAX_BLOCK_WRITE_LENGTH -
+                        (MXL_HYDRA_I2C_HDR_SIZE +
+                         MXL_HYDRA_REG_SIZE_IN_BYTES)) / 4) * 4;
+       u8 w_msg_buffer[MXL_HYDRA_OEM_MAX_BLOCK_WRITE_LENGTH -
+                     (MXL_HYDRA_I2C_HDR_SIZE + MXL_HYDRA_REG_SIZE_IN_BYTES)];
+
+       do {
+               size = orig_size = (((u32)(data_count + block_size)) > total_size) ?
+                       (total_size - data_count) : block_size;
+
+               if (orig_size & 3)
+                       size = (orig_size + 4) & ~3;
+               w_buf_ptr = &w_msg_buffer[0];
+               memset((void *) w_buf_ptr, 0, size);
+               memcpy((void *) w_buf_ptr, (void *) data_ptr, orig_size);
+               convert_endian(1, size, w_buf_ptr);
+               status  = write_firmware_block(state, mem_addr, size, w_buf_ptr);
+               if (status)
+                       return status;
+               data_count += size;
+               mem_addr   += size;
+               data_ptr   += size;
+       } while (data_count < total_size);
+
+       return status;
+}
+
+static int do_firmware_download(struct mxl *state, u8 *mbin_buffer_ptr,
+                               u32 mbin_buffer_size)
+
+{
+       int status;
+       u32 index = 0;
+       u32 seg_length = 0;
+       u32 seg_address = 0;
+       struct MBIN_FILE_T *mbin_ptr  = (struct MBIN_FILE_T *)mbin_buffer_ptr;
+       struct MBIN_SEGMENT_T *segment_ptr;
+       enum MXL_BOOL_E xcpu_fw_flag = MXL_FALSE;
+
+       if (mbin_ptr->header.id != MBIN_FILE_HEADER_ID) {
+               dev_err(state->i2cdev, "%s: Invalid file header ID (%c)\n",
+                      __func__, mbin_ptr->header.id);
+               return -EINVAL;
+       }
+       status = write_register(state, FW_DL_SIGN_ADDR, 0);
+       if (status)
+               return status;
+       segment_ptr = (struct MBIN_SEGMENT_T *) (&mbin_ptr->data[0]);
+       for (index = 0; index < mbin_ptr->header.num_segments; index++) {
+               if (segment_ptr->header.id != MBIN_SEGMENT_HEADER_ID) {
+                       dev_err(state->i2cdev, "%s: Invalid segment header ID (%c)\n",
+                              __func__, segment_ptr->header.id);
+                       return -EINVAL;
+               }
+               seg_length  = get_big_endian(24,
+                                           &(segment_ptr->header.len24[0]));
+               seg_address = get_big_endian(32,
+                                           &(segment_ptr->header.address[0]));
+
+               if (state->base->type == MXL_HYDRA_DEVICE_568) {
+                       if ((((seg_address & 0x90760000) == 0x90760000) ||
+                            ((seg_address & 0x90740000) == 0x90740000)) &&
+                           (xcpu_fw_flag == MXL_FALSE)) {
+                               update_by_mnemonic(state, 0x8003003C, 0, 1, 1);
+                               msleep(200);
+                               write_register(state, 0x90720000, 0);
+                               usleep_range(10000, 11000);
+                               xcpu_fw_flag = MXL_TRUE;
+                       }
+                       status = write_fw_segment(state, seg_address,
+                                                 seg_length,
+                                                 (u8 *) segment_ptr->data);
+               } else {
+                       if (((seg_address & 0x90760000) != 0x90760000) &&
+                           ((seg_address & 0x90740000) != 0x90740000))
+                               status = write_fw_segment(state, seg_address,
+                                       seg_length, (u8 *) segment_ptr->data);
+               }
+               if (status)
+                       return status;
+               segment_ptr = (struct MBIN_SEGMENT_T *)
+                       &(segment_ptr->data[((seg_length + 3) / 4) * 4]);
+       }
+       return status;
+}
+
+static int check_fw(struct mxl *state, u8 *mbin, u32 mbin_len)
+{
+       struct MBIN_FILE_HEADER_T *fh = (struct MBIN_FILE_HEADER_T *) mbin;
+       u32 flen = (fh->image_size24[0] << 16) |
+               (fh->image_size24[1] <<  8) | fh->image_size24[2];
+       u8 *fw, cs = 0;
+       u32 i;
+
+       if (fh->id != 'M' || fh->fmt_version != '1' || flen > 0x3FFF0) {
+               dev_info(state->i2cdev, "Invalid FW Header\n");
+               return -1;
+       }
+       fw = mbin + sizeof(struct MBIN_FILE_HEADER_T);
+       for (i = 0; i < flen; i += 1)
+               cs += fw[i];
+       if (cs != fh->image_checksum) {
+               dev_info(state->i2cdev, "Invalid FW Checksum\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int firmware_download(struct mxl *state, u8 *mbin, u32 mbin_len)
+{
+       int status;
+       u32 reg_data = 0;
+       struct MXL_HYDRA_SKU_COMMAND_T dev_sku_cfg;
+       u8 cmd_size = sizeof(struct MXL_HYDRA_SKU_COMMAND_T);
+       u8 cmd_buff[sizeof(struct MXL_HYDRA_SKU_COMMAND_T) + 6];
+
+       if (check_fw(state, mbin, mbin_len))
+               return -1;
+
+       /* put CPU into reset */
+       status = update_by_mnemonic(state, 0x8003003C, 0, 1, 0);
+       if (status)
+               return status;
+       usleep_range(1000, 2000);
+
+       /* Reset TX FIFO's, BBAND, XBAR */
+       status = write_register(state, HYDRA_RESET_TRANSPORT_FIFO_REG,
+                               HYDRA_RESET_TRANSPORT_FIFO_DATA);
+       if (status)
+               return status;
+       status = write_register(state, HYDRA_RESET_BBAND_REG,
+                               HYDRA_RESET_BBAND_DATA);
+       if (status)
+               return status;
+       status = write_register(state, HYDRA_RESET_XBAR_REG,
+                               HYDRA_RESET_XBAR_DATA);
+       if (status)
+               return status;
+
+       /* Disable clock to Baseband, Wideband, SerDes,
+        * Alias ext & Transport modules
+        */
+       status = write_register(state, HYDRA_MODULES_CLK_2_REG,
+                               HYDRA_DISABLE_CLK_2);
+       if (status)
+               return status;
+       /* Clear Software & Host interrupt status - (Clear on read) */
+       status = read_register(state, HYDRA_PRCM_ROOT_CLK_REG, &reg_data);
+       if (status)
+               return status;
+       status = do_firmware_download(state, mbin, mbin_len);
+       if (status)
+               return status;
+
+       if (state->base->type == MXL_HYDRA_DEVICE_568) {
+               usleep_range(10000, 11000);
+
+               /* bring XCPU out of reset */
+               status = write_register(state, 0x90720000, 1);
+               if (status)
+                       return status;
+               msleep(500);
+
+               /* Enable XCPU UART message processing in MCPU */
+               status = write_register(state, 0x9076B510, 1);
+               if (status)
+                       return status;
+       } else {
+               /* Bring CPU out of reset */
+               status = update_by_mnemonic(state, 0x8003003C, 0, 1, 1);
+               if (status)
+                       return status;
+               /* Wait until FW boots */
+               msleep(150);
+       }
+
+       /* Initialize XPT XBAR */
+       status = write_register(state, XPT_DMD0_BASEADDR, 0x76543210);
+       if (status)
+               return status;
+
+       if (!firmware_is_alive(state))
+               return -1;
+
+       dev_info(state->i2cdev, "Hydra FW alive. Hail!\n");
+
+       /* sometimes register values are wrong shortly
+        * after first heart beats
+        */
+       msleep(50);
+
+       dev_sku_cfg.sku_type = state->base->sku_type;
+       BUILD_HYDRA_CMD(MXL_HYDRA_DEV_CFG_SKU_CMD, MXL_CMD_WRITE,
+                       cmd_size, &dev_sku_cfg, cmd_buff);
+       status = send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE,
+                             &cmd_buff[0]);
+
+       return status;
+}
+
+static int cfg_ts_pad_mux(struct mxl *state, enum MXL_BOOL_E enable_serial_ts)
+{
+       int status = 0;
+       u32 pad_mux_value = 0;
+
+       if (enable_serial_ts == MXL_TRUE) {
+               pad_mux_value = 0;
+               if ((state->base->type == MXL_HYDRA_DEVICE_541) ||
+                   (state->base->type == MXL_HYDRA_DEVICE_541S))
+                       pad_mux_value = 2;
+       } else {
+               if ((state->base->type == MXL_HYDRA_DEVICE_581) ||
+                   (state->base->type == MXL_HYDRA_DEVICE_581S))
+                       pad_mux_value = 2;
+               else
+                       pad_mux_value = 3;
+       }
+
+       switch (state->base->type) {
+       case MXL_HYDRA_DEVICE_561:
+       case MXL_HYDRA_DEVICE_581:
+       case MXL_HYDRA_DEVICE_541:
+       case MXL_HYDRA_DEVICE_541S:
+       case MXL_HYDRA_DEVICE_561S:
+       case MXL_HYDRA_DEVICE_581S:
+               status |= update_by_mnemonic(state, 0x90000170, 24, 3,
+                                            pad_mux_value);
+               status |= update_by_mnemonic(state, 0x90000170, 28, 3,
+                                            pad_mux_value);
+               status |= update_by_mnemonic(state, 0x90000174, 0, 3,
+                                            pad_mux_value);
+               status |= update_by_mnemonic(state, 0x90000174, 4, 3,
+                                            pad_mux_value);
+               status |= update_by_mnemonic(state, 0x90000174, 8, 3,
+                                            pad_mux_value);
+               status |= update_by_mnemonic(state, 0x90000174, 12, 3,
+                                            pad_mux_value);
+               status |= update_by_mnemonic(state, 0x90000174, 16, 3,
+                                            pad_mux_value);
+               status |= update_by_mnemonic(state, 0x90000174, 20, 3,
+                                            pad_mux_value);
+               status |= update_by_mnemonic(state, 0x90000174, 24, 3,
+                                            pad_mux_value);
+               status |= update_by_mnemonic(state, 0x90000174, 28, 3,
+                                            pad_mux_value);
+               status |= update_by_mnemonic(state, 0x90000178, 0, 3,
+                                            pad_mux_value);
+               status |= update_by_mnemonic(state, 0x90000178, 4, 3,
+                                            pad_mux_value);
+               status |= update_by_mnemonic(state, 0x90000178, 8, 3,
+                                            pad_mux_value);
+               break;
+
+       case MXL_HYDRA_DEVICE_544:
+       case MXL_HYDRA_DEVICE_542:
+               status |= update_by_mnemonic(state, 0x9000016C, 4, 3, 1);
+               status |= update_by_mnemonic(state, 0x9000016C, 8, 3, 0);
+               status |= update_by_mnemonic(state, 0x9000016C, 12, 3, 0);
+               status |= update_by_mnemonic(state, 0x9000016C, 16, 3, 0);
+               status |= update_by_mnemonic(state, 0x90000170, 0, 3, 0);
+               status |= update_by_mnemonic(state, 0x90000178, 12, 3, 1);
+               status |= update_by_mnemonic(state, 0x90000178, 16, 3, 1);
+               status |= update_by_mnemonic(state, 0x90000178, 20, 3, 1);
+               status |= update_by_mnemonic(state, 0x90000178, 24, 3, 1);
+               status |= update_by_mnemonic(state, 0x9000017C, 0, 3, 1);
+               status |= update_by_mnemonic(state, 0x9000017C, 4, 3, 1);
+               if (enable_serial_ts == MXL_ENABLE) {
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 4, 3, 0);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 8, 3, 0);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 12, 3, 0);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 16, 3, 0);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 20, 3, 1);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 24, 3, 1);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 28, 3, 2);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 0, 3, 2);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 4, 3, 2);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 8, 3, 2);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 12, 3, 2);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 16, 3, 2);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 20, 3, 2);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 24, 3, 2);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 28, 3, 2);
+                       status |= update_by_mnemonic(state,
+                               0x90000178, 0, 3, 2);
+                       status |= update_by_mnemonic(state,
+                               0x90000178, 4, 3, 2);
+                       status |= update_by_mnemonic(state,
+                               0x90000178, 8, 3, 2);
+               } else {
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 4, 3, 3);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 8, 3, 3);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 12, 3, 3);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 16, 3, 3);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 20, 3, 3);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 24, 3, 3);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 28, 3, 3);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 0, 3, 3);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 4, 3, 3);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 8, 3, 3);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 12, 3, 3);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 16, 3, 3);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 20, 3, 1);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 24, 3, 1);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 28, 3, 1);
+                       status |= update_by_mnemonic(state,
+                               0x90000178, 0, 3, 1);
+                       status |= update_by_mnemonic(state,
+                               0x90000178, 4, 3, 1);
+                       status |= update_by_mnemonic(state,
+                               0x90000178, 8, 3, 1);
+               }
+               break;
+
+       case MXL_HYDRA_DEVICE_568:
+               if (enable_serial_ts == MXL_FALSE) {
+                       status |= update_by_mnemonic(state,
+                               0x9000016C, 8, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x9000016C, 12, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x9000016C, 16, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x9000016C, 20, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x9000016C, 24, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x9000016C, 28, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 0, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 4, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 8, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 12, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 16, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 20, 3, 5);
+
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 24, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 0, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 4, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 8, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 12, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 16, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 20, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 24, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 28, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000178, 0, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000178, 4, 3, pad_mux_value);
+
+                       status |= update_by_mnemonic(state,
+                               0x90000178, 8, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x90000178, 12, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x90000178, 16, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x90000178, 20, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x90000178, 24, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x90000178, 28, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x9000017C, 0, 3, 5);
+                       status |= update_by_mnemonic(state,
+                               0x9000017C, 4, 3, 5);
+               } else {
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 4, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 8, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 12, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 16, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 20, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 24, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000170, 28, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 0, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 4, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 8, 3, pad_mux_value);
+                       status |= update_by_mnemonic(state,
+                               0x90000174, 12, 3, pad_mux_value);
+               }
+               break;
+
+
+       case MXL_HYDRA_DEVICE_584:
+       default:
+               status |= update_by_mnemonic(state,
+                       0x90000170, 4, 3, pad_mux_value);
+               status |= update_by_mnemonic(state,
+                       0x90000170, 8, 3, pad_mux_value);
+               status |= update_by_mnemonic(state,
+                       0x90000170, 12, 3, pad_mux_value);
+               status |= update_by_mnemonic(state,
+                       0x90000170, 16, 3, pad_mux_value);
+               status |= update_by_mnemonic(state,
+                       0x90000170, 20, 3, pad_mux_value);
+               status |= update_by_mnemonic(state,
+                       0x90000170, 24, 3, pad_mux_value);
+               status |= update_by_mnemonic(state,
+                       0x90000170, 28, 3, pad_mux_value);
+               status |= update_by_mnemonic(state,
+                       0x90000174, 0, 3, pad_mux_value);
+               status |= update_by_mnemonic(state,
+                       0x90000174, 4, 3, pad_mux_value);
+               status |= update_by_mnemonic(state,
+                       0x90000174, 8, 3, pad_mux_value);
+               status |= update_by_mnemonic(state,
+                       0x90000174, 12, 3, pad_mux_value);
+               break;
+       }
+       return status;
+}
+
+static int set_drive_strength(struct mxl *state,
+               enum MXL_HYDRA_TS_DRIVE_STRENGTH_E ts_drive_strength)
+{
+       int stat = 0;
+       u32 val;
+
+       read_register(state, 0x90000194, &val);
+       dev_info(state->i2cdev, "DIGIO = %08x\n", val);
+       dev_info(state->i2cdev, "set drive_strength = %u\n", ts_drive_strength);
+
+
+       stat |= update_by_mnemonic(state, 0x90000194, 0, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x90000194, 20, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x90000194, 24, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x90000198, 12, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x90000198, 16, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x90000198, 20, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x90000198, 24, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x9000019C, 0, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x9000019C, 4, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x9000019C, 8, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x9000019C, 24, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x9000019C, 28, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x900001A0, 0, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x900001A0, 4, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x900001A0, 20, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x900001A0, 24, 3, ts_drive_strength);
+       stat |= update_by_mnemonic(state, 0x900001A0, 28, 3, ts_drive_strength);
+
+       return stat;
+}
+
+static int enable_tuner(struct mxl *state, u32 tuner, u32 enable)
+{
+       int stat = 0;
+       struct MXL_HYDRA_TUNER_CMD ctrl_tuner_cmd;
+       u8 cmd_size = sizeof(ctrl_tuner_cmd);
+       u8 cmd_buff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN];
+       u32 val, count = 10;
+
+       ctrl_tuner_cmd.tuner_id = tuner;
+       ctrl_tuner_cmd.enable = enable;
+       BUILD_HYDRA_CMD(MXL_HYDRA_TUNER_ACTIVATE_CMD, MXL_CMD_WRITE,
+                       cmd_size, &ctrl_tuner_cmd, cmd_buff);
+       stat = send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE,
+                           &cmd_buff[0]);
+       if (stat)
+               return stat;
+       read_register(state, HYDRA_TUNER_ENABLE_COMPLETE, &val);
+       while (--count && ((val >> tuner) & 1) != enable) {
+               msleep(20);
+               read_register(state, HYDRA_TUNER_ENABLE_COMPLETE, &val);
+       }
+       if (!count)
+               return -1;
+       read_register(state, HYDRA_TUNER_ENABLE_COMPLETE, &val);
+       dev_dbg(state->i2cdev, "tuner %u ready = %u\n",
+               tuner, (val >> tuner) & 1);
+
+       return 0;
+}
+
+
+static int config_ts(struct mxl *state, enum MXL_HYDRA_DEMOD_ID_E demod_id,
+                    struct MXL_HYDRA_MPEGOUT_PARAM_T *mpeg_out_param_ptr)
+{
+       int status = 0;
+       u32 nco_count_min = 0;
+       u32 clk_type = 0;
+
+       struct MXL_REG_FIELD_T xpt_sync_polarity[MXL_HYDRA_DEMOD_MAX] = {
+               {0x90700010, 8, 1}, {0x90700010, 9, 1},
+               {0x90700010, 10, 1}, {0x90700010, 11, 1},
+               {0x90700010, 12, 1}, {0x90700010, 13, 1},
+               {0x90700010, 14, 1}, {0x90700010, 15, 1} };
+       struct MXL_REG_FIELD_T xpt_clock_polarity[MXL_HYDRA_DEMOD_MAX] = {
+               {0x90700010, 16, 1}, {0x90700010, 17, 1},
+               {0x90700010, 18, 1}, {0x90700010, 19, 1},
+               {0x90700010, 20, 1}, {0x90700010, 21, 1},
+               {0x90700010, 22, 1}, {0x90700010, 23, 1} };
+       struct MXL_REG_FIELD_T xpt_valid_polarity[MXL_HYDRA_DEMOD_MAX] = {
+               {0x90700014, 0, 1}, {0x90700014, 1, 1},
+               {0x90700014, 2, 1}, {0x90700014, 3, 1},
+               {0x90700014, 4, 1}, {0x90700014, 5, 1},
+               {0x90700014, 6, 1}, {0x90700014, 7, 1} };
+       struct MXL_REG_FIELD_T xpt_ts_clock_phase[MXL_HYDRA_DEMOD_MAX] = {
+               {0x90700018, 0, 3}, {0x90700018, 4, 3},
+               {0x90700018, 8, 3}, {0x90700018, 12, 3},
+               {0x90700018, 16, 3}, {0x90700018, 20, 3},
+               {0x90700018, 24, 3}, {0x90700018, 28, 3} };
+       struct MXL_REG_FIELD_T xpt_lsb_first[MXL_HYDRA_DEMOD_MAX] = {
+               {0x9070000C, 16, 1}, {0x9070000C, 17, 1},
+               {0x9070000C, 18, 1}, {0x9070000C, 19, 1},
+               {0x9070000C, 20, 1}, {0x9070000C, 21, 1},
+               {0x9070000C, 22, 1}, {0x9070000C, 23, 1} };
+       struct MXL_REG_FIELD_T xpt_sync_byte[MXL_HYDRA_DEMOD_MAX] = {
+               {0x90700010, 0, 1}, {0x90700010, 1, 1},
+               {0x90700010, 2, 1}, {0x90700010, 3, 1},
+               {0x90700010, 4, 1}, {0x90700010, 5, 1},
+               {0x90700010, 6, 1}, {0x90700010, 7, 1} };
+       struct MXL_REG_FIELD_T xpt_enable_output[MXL_HYDRA_DEMOD_MAX] = {
+               {0x9070000C, 0, 1}, {0x9070000C, 1, 1},
+               {0x9070000C, 2, 1}, {0x9070000C, 3, 1},
+               {0x9070000C, 4, 1}, {0x9070000C, 5, 1},
+               {0x9070000C, 6, 1}, {0x9070000C, 7, 1} };
+       struct MXL_REG_FIELD_T xpt_err_replace_sync[MXL_HYDRA_DEMOD_MAX] = {
+               {0x9070000C, 24, 1}, {0x9070000C, 25, 1},
+               {0x9070000C, 26, 1}, {0x9070000C, 27, 1},
+               {0x9070000C, 28, 1}, {0x9070000C, 29, 1},
+               {0x9070000C, 30, 1}, {0x9070000C, 31, 1} };
+       struct MXL_REG_FIELD_T xpt_err_replace_valid[MXL_HYDRA_DEMOD_MAX] = {
+               {0x90700014, 8, 1}, {0x90700014, 9, 1},
+               {0x90700014, 10, 1}, {0x90700014, 11, 1},
+               {0x90700014, 12, 1}, {0x90700014, 13, 1},
+               {0x90700014, 14, 1}, {0x90700014, 15, 1} };
+       struct MXL_REG_FIELD_T xpt_continuous_clock[MXL_HYDRA_DEMOD_MAX] = {
+               {0x907001D4, 0, 1}, {0x907001D4, 1, 1},
+               {0x907001D4, 2, 1}, {0x907001D4, 3, 1},
+               {0x907001D4, 4, 1}, {0x907001D4, 5, 1},
+               {0x907001D4, 6, 1}, {0x907001D4, 7, 1} };
+       struct MXL_REG_FIELD_T xpt_nco_clock_rate[MXL_HYDRA_DEMOD_MAX] = {
+               {0x90700044, 16, 80}, {0x90700044, 16, 81},
+               {0x90700044, 16, 82}, {0x90700044, 16, 83},
+               {0x90700044, 16, 84}, {0x90700044, 16, 85},
+               {0x90700044, 16, 86}, {0x90700044, 16, 87} };
+
+       demod_id = state->base->ts_map[demod_id];
+
+       if (mpeg_out_param_ptr->enable == MXL_ENABLE) {
+               if (mpeg_out_param_ptr->mpeg_mode ==
+                   MXL_HYDRA_MPEG_MODE_PARALLEL) {
+               } else {
+                       cfg_ts_pad_mux(state, MXL_TRUE);
+                       update_by_mnemonic(state,
+                               0x90700010, 27, 1, MXL_FALSE);
+               }
+       }
+
+       nco_count_min =
+               (u32)(MXL_HYDRA_NCO_CLK / mpeg_out_param_ptr->max_mpeg_clk_rate);
+
+       if (state->base->chipversion >= 2) {
+               status |= update_by_mnemonic(state,
+                       xpt_nco_clock_rate[demod_id].reg_addr, /* Reg Addr */
+                       xpt_nco_clock_rate[demod_id].lsb_pos, /* LSB pos */
+                       xpt_nco_clock_rate[demod_id].num_of_bits, /* Num of bits */
+                       nco_count_min); /* Data */
+       } else
+               update_by_mnemonic(state, 0x90700044, 16, 8, nco_count_min);
+
+       if (mpeg_out_param_ptr->mpeg_clk_type == MXL_HYDRA_MPEG_CLK_CONTINUOUS)
+               clk_type = 1;
+
+       if (mpeg_out_param_ptr->mpeg_mode < MXL_HYDRA_MPEG_MODE_PARALLEL) {
+               status |= update_by_mnemonic(state,
+                       xpt_continuous_clock[demod_id].reg_addr,
+                       xpt_continuous_clock[demod_id].lsb_pos,
+                       xpt_continuous_clock[demod_id].num_of_bits,
+                       clk_type);
+       } else
+               update_by_mnemonic(state, 0x907001D4, 8, 1, clk_type);
+
+       status |= update_by_mnemonic(state,
+               xpt_sync_polarity[demod_id].reg_addr,
+               xpt_sync_polarity[demod_id].lsb_pos,
+               xpt_sync_polarity[demod_id].num_of_bits,
+               mpeg_out_param_ptr->mpeg_sync_pol);
+
+       status |= update_by_mnemonic(state,
+               xpt_valid_polarity[demod_id].reg_addr,
+               xpt_valid_polarity[demod_id].lsb_pos,
+               xpt_valid_polarity[demod_id].num_of_bits,
+               mpeg_out_param_ptr->mpeg_valid_pol);
+
+       status |= update_by_mnemonic(state,
+               xpt_clock_polarity[demod_id].reg_addr,
+               xpt_clock_polarity[demod_id].lsb_pos,
+               xpt_clock_polarity[demod_id].num_of_bits,
+               mpeg_out_param_ptr->mpeg_clk_pol);
+
+       status |= update_by_mnemonic(state,
+               xpt_sync_byte[demod_id].reg_addr,
+               xpt_sync_byte[demod_id].lsb_pos,
+               xpt_sync_byte[demod_id].num_of_bits,
+               mpeg_out_param_ptr->mpeg_sync_pulse_width);
+
+       status |= update_by_mnemonic(state,
+               xpt_ts_clock_phase[demod_id].reg_addr,
+               xpt_ts_clock_phase[demod_id].lsb_pos,
+               xpt_ts_clock_phase[demod_id].num_of_bits,
+               mpeg_out_param_ptr->mpeg_clk_phase);
+
+       status |= update_by_mnemonic(state,
+               xpt_lsb_first[demod_id].reg_addr,
+               xpt_lsb_first[demod_id].lsb_pos,
+               xpt_lsb_first[demod_id].num_of_bits,
+               mpeg_out_param_ptr->lsb_or_msb_first);
+
+       switch (mpeg_out_param_ptr->mpeg_error_indication) {
+       case MXL_HYDRA_MPEG_ERR_REPLACE_SYNC:
+               status |= update_by_mnemonic(state,
+                       xpt_err_replace_sync[demod_id].reg_addr,
+                       xpt_err_replace_sync[demod_id].lsb_pos,
+                       xpt_err_replace_sync[demod_id].num_of_bits,
+                       MXL_TRUE);
+               status |= update_by_mnemonic(state,
+                       xpt_err_replace_valid[demod_id].reg_addr,
+                       xpt_err_replace_valid[demod_id].lsb_pos,
+                       xpt_err_replace_valid[demod_id].num_of_bits,
+                       MXL_FALSE);
+               break;
+
+       case MXL_HYDRA_MPEG_ERR_REPLACE_VALID:
+               status |= update_by_mnemonic(state,
+                       xpt_err_replace_sync[demod_id].reg_addr,
+                       xpt_err_replace_sync[demod_id].lsb_pos,
+                       xpt_err_replace_sync[demod_id].num_of_bits,
+                       MXL_FALSE);
+
+               status |= update_by_mnemonic(state,
+                       xpt_err_replace_valid[demod_id].reg_addr,
+                       xpt_err_replace_valid[demod_id].lsb_pos,
+                       xpt_err_replace_valid[demod_id].num_of_bits,
+                       MXL_TRUE);
+               break;
+
+       case MXL_HYDRA_MPEG_ERR_INDICATION_DISABLED:
+       default:
+               status |= update_by_mnemonic(state,
+                       xpt_err_replace_sync[demod_id].reg_addr,
+                       xpt_err_replace_sync[demod_id].lsb_pos,
+                       xpt_err_replace_sync[demod_id].num_of_bits,
+                       MXL_FALSE);
+
+               status |= update_by_mnemonic(state,
+                       xpt_err_replace_valid[demod_id].reg_addr,
+                       xpt_err_replace_valid[demod_id].lsb_pos,
+                       xpt_err_replace_valid[demod_id].num_of_bits,
+                       MXL_FALSE);
+
+               break;
+
+       }
+
+       if (mpeg_out_param_ptr->mpeg_mode != MXL_HYDRA_MPEG_MODE_PARALLEL) {
+               status |= update_by_mnemonic(state,
+                       xpt_enable_output[demod_id].reg_addr,
+                       xpt_enable_output[demod_id].lsb_pos,
+                       xpt_enable_output[demod_id].num_of_bits,
+                       mpeg_out_param_ptr->enable);
+       }
+       return status;
+}
+
+static int config_mux(struct mxl *state)
+{
+       update_by_mnemonic(state, 0x9070000C, 0, 1, 0);
+       update_by_mnemonic(state, 0x9070000C, 1, 1, 0);
+       update_by_mnemonic(state, 0x9070000C, 2, 1, 0);
+       update_by_mnemonic(state, 0x9070000C, 3, 1, 0);
+       update_by_mnemonic(state, 0x9070000C, 4, 1, 0);
+       update_by_mnemonic(state, 0x9070000C, 5, 1, 0);
+       update_by_mnemonic(state, 0x9070000C, 6, 1, 0);
+       update_by_mnemonic(state, 0x9070000C, 7, 1, 0);
+       update_by_mnemonic(state, 0x90700008, 0, 2, 1);
+       update_by_mnemonic(state, 0x90700008, 2, 2, 1);
+       return 0;
+}
+
+static int load_fw(struct mxl *state, struct mxl5xx_cfg *cfg)
+{
+       int stat = 0;
+       u8 *buf;
+
+       if (cfg->fw)
+               return firmware_download(state, cfg->fw, cfg->fw_len);
+
+       if (!cfg->fw_read)
+               return -1;
+
+       buf = vmalloc(0x40000);
+       if (!buf)
+               return -ENOMEM;
+
+       cfg->fw_read(cfg->fw_priv, buf, 0x40000);
+       stat = firmware_download(state, buf, 0x40000);
+       vfree(buf);
+
+       return stat;
+}
+
+static int validate_sku(struct mxl *state)
+{
+       u32 pad_mux_bond = 0, prcm_chip_id = 0, prcm_so_cid = 0;
+       int status;
+       u32 type = state->base->type;
+
+       status = read_by_mnemonic(state, 0x90000190, 0, 3, &pad_mux_bond);
+       status |= read_by_mnemonic(state, 0x80030000, 0, 12, &prcm_chip_id);
+       status |= read_by_mnemonic(state, 0x80030004, 24, 8, &prcm_so_cid);
+       if (status)
+               return -1;
+
+       dev_info(state->i2cdev, "padMuxBond=%08x, prcmChipId=%08x, prcmSoCId=%08x\n",
+               pad_mux_bond, prcm_chip_id, prcm_so_cid);
+
+       if (prcm_chip_id != 0x560) {
+               switch (pad_mux_bond) {
+               case MXL_HYDRA_SKU_ID_581:
+                       if (type == MXL_HYDRA_DEVICE_581)
+                               return 0;
+                       if (type == MXL_HYDRA_DEVICE_581S) {
+                               state->base->type = MXL_HYDRA_DEVICE_581;
+                               return 0;
+                       }
+                       break;
+               case MXL_HYDRA_SKU_ID_584:
+                       if (type == MXL_HYDRA_DEVICE_584)
+                               return 0;
+                       break;
+               case MXL_HYDRA_SKU_ID_544:
+                       if (type == MXL_HYDRA_DEVICE_544)
+                               return 0;
+                       if (type == MXL_HYDRA_DEVICE_542)
+                               return 0;
+                       break;
+               case MXL_HYDRA_SKU_ID_582:
+                       if (type == MXL_HYDRA_DEVICE_582)
+                               return 0;
+                       break;
+               default:
+                       return -1;
+               }
+       } else {
+
+       }
+       return -1;
+}
+
+static int get_fwinfo(struct mxl *state)
+{
+       int status;
+       u32 val = 0;
+
+       status = read_by_mnemonic(state, 0x90000190, 0, 3, &val);
+       if (status)
+               return status;
+       dev_info(state->i2cdev, "chipID=%08x\n", val);
+
+       status = read_by_mnemonic(state, 0x80030004, 8, 8, &val);
+       if (status)
+               return status;
+       dev_info(state->i2cdev, "chipVer=%08x\n", val);
+
+       status = read_register(state, HYDRA_FIRMWARE_VERSION, &val);
+       if (status)
+               return status;
+       dev_info(state->i2cdev, "FWVer=%08x\n", val);
+
+       state->base->fwversion = val;
+       return status;
+}
+
+
+static u8 ts_map1_to_1[MXL_HYDRA_DEMOD_MAX] = {
+       MXL_HYDRA_DEMOD_ID_0,
+       MXL_HYDRA_DEMOD_ID_1,
+       MXL_HYDRA_DEMOD_ID_2,
+       MXL_HYDRA_DEMOD_ID_3,
+       MXL_HYDRA_DEMOD_ID_4,
+       MXL_HYDRA_DEMOD_ID_5,
+       MXL_HYDRA_DEMOD_ID_6,
+       MXL_HYDRA_DEMOD_ID_7,
+};
+
+static u8 ts_map54x[MXL_HYDRA_DEMOD_MAX] = {
+       MXL_HYDRA_DEMOD_ID_2,
+       MXL_HYDRA_DEMOD_ID_3,
+       MXL_HYDRA_DEMOD_ID_4,
+       MXL_HYDRA_DEMOD_ID_5,
+       MXL_HYDRA_DEMOD_MAX,
+       MXL_HYDRA_DEMOD_MAX,
+       MXL_HYDRA_DEMOD_MAX,
+       MXL_HYDRA_DEMOD_MAX,
+};
+
+static int probe(struct mxl *state, struct mxl5xx_cfg *cfg)
+{
+       u32 chipver;
+       int fw, status, j;
+       struct MXL_HYDRA_MPEGOUT_PARAM_T mpeg_interface_cfg;
+
+       state->base->ts_map = ts_map1_to_1;
+
+       switch (state->base->type) {
+       case MXL_HYDRA_DEVICE_581:
+       case MXL_HYDRA_DEVICE_581S:
+               state->base->can_clkout = 1;
+               state->base->demod_num = 8;
+               state->base->tuner_num = 1;
+               state->base->sku_type = MXL_HYDRA_SKU_TYPE_581;
+               break;
+       case MXL_HYDRA_DEVICE_582:
+               state->base->can_clkout = 1;
+               state->base->demod_num = 8;
+               state->base->tuner_num = 3;
+               state->base->sku_type = MXL_HYDRA_SKU_TYPE_582;
+               break;
+       case MXL_HYDRA_DEVICE_585:
+               state->base->can_clkout = 0;
+               state->base->demod_num = 8;
+               state->base->tuner_num = 4;
+               state->base->sku_type = MXL_HYDRA_SKU_TYPE_585;
+               break;
+       case MXL_HYDRA_DEVICE_544:
+               state->base->can_clkout = 0;
+               state->base->demod_num = 4;
+               state->base->tuner_num = 4;
+               state->base->sku_type = MXL_HYDRA_SKU_TYPE_544;
+               state->base->ts_map = ts_map54x;
+               break;
+       case MXL_HYDRA_DEVICE_541:
+       case MXL_HYDRA_DEVICE_541S:
+               state->base->can_clkout = 0;
+               state->base->demod_num = 4;
+               state->base->tuner_num = 1;
+               state->base->sku_type = MXL_HYDRA_SKU_TYPE_541;
+               state->base->ts_map = ts_map54x;
+               break;
+       case MXL_HYDRA_DEVICE_561:
+       case MXL_HYDRA_DEVICE_561S:
+               state->base->can_clkout = 0;
+               state->base->demod_num = 6;
+               state->base->tuner_num = 1;
+               state->base->sku_type = MXL_HYDRA_SKU_TYPE_561;
+               break;
+       case MXL_HYDRA_DEVICE_568:
+               state->base->can_clkout = 0;
+               state->base->demod_num = 8;
+               state->base->tuner_num = 1;
+               state->base->chan_bond = 1;
+               state->base->sku_type = MXL_HYDRA_SKU_TYPE_568;
+               break;
+       case MXL_HYDRA_DEVICE_542:
+               state->base->can_clkout = 1;
+               state->base->demod_num = 4;
+               state->base->tuner_num = 3;
+               state->base->sku_type = MXL_HYDRA_SKU_TYPE_542;
+               state->base->ts_map = ts_map54x;
+               break;
+       case MXL_HYDRA_DEVICE_TEST:
+       case MXL_HYDRA_DEVICE_584:
+       default:
+               state->base->can_clkout = 0;
+               state->base->demod_num = 8;
+               state->base->tuner_num = 4;
+               state->base->sku_type = MXL_HYDRA_SKU_TYPE_584;
+               break;
+       }
+
+       status = validate_sku(state);
+       if (status)
+               return status;
+
+       update_by_mnemonic(state, 0x80030014, 9, 1, 1);
+       update_by_mnemonic(state, 0x8003003C, 12, 1, 1);
+       status = read_by_mnemonic(state, 0x80030000, 12, 4, &chipver);
+       if (status)
+               state->base->chipversion = 0;
+       else
+               state->base->chipversion = (chipver == 2) ? 2 : 1;
+       dev_info(state->i2cdev, "Hydra chip version %u\n",
+               state->base->chipversion);
+
+       cfg_dev_xtal(state, cfg->clk, cfg->cap, 0);
+
+       fw = firmware_is_alive(state);
+       if (!fw) {
+               status = load_fw(state, cfg);
+               if (status)
+                       return status;
+       }
+       get_fwinfo(state);
+
+       config_mux(state);
+       mpeg_interface_cfg.enable = MXL_ENABLE;
+       mpeg_interface_cfg.lsb_or_msb_first = MXL_HYDRA_MPEG_SERIAL_MSB_1ST;
+       /*  supports only (0-104&139)MHz */
+       if (cfg->ts_clk)
+               mpeg_interface_cfg.max_mpeg_clk_rate = cfg->ts_clk;
+       else
+               mpeg_interface_cfg.max_mpeg_clk_rate = 69; /* 139; */
+       mpeg_interface_cfg.mpeg_clk_phase = MXL_HYDRA_MPEG_CLK_PHASE_SHIFT_0_DEG;
+       mpeg_interface_cfg.mpeg_clk_pol = MXL_HYDRA_MPEG_CLK_IN_PHASE;
+       /* MXL_HYDRA_MPEG_CLK_GAPPED; */
+       mpeg_interface_cfg.mpeg_clk_type = MXL_HYDRA_MPEG_CLK_CONTINUOUS;
+       mpeg_interface_cfg.mpeg_error_indication =
+               MXL_HYDRA_MPEG_ERR_INDICATION_DISABLED;
+       mpeg_interface_cfg.mpeg_mode = MXL_HYDRA_MPEG_MODE_SERIAL_3_WIRE;
+       mpeg_interface_cfg.mpeg_sync_pol  = MXL_HYDRA_MPEG_ACTIVE_HIGH;
+       mpeg_interface_cfg.mpeg_sync_pulse_width  = MXL_HYDRA_MPEG_SYNC_WIDTH_BIT;
+       mpeg_interface_cfg.mpeg_valid_pol  = MXL_HYDRA_MPEG_ACTIVE_HIGH;
+
+       for (j = 0; j < state->base->demod_num; j++) {
+               status = config_ts(state, (enum MXL_HYDRA_DEMOD_ID_E) j,
+                                  &mpeg_interface_cfg);
+               if (status)
+                       return status;
+       }
+       set_drive_strength(state, 1);
+       return 0;
+}
+
+struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c,
+       struct mxl5xx_cfg *cfg, u32 demod, u32 tuner,
+       int (**fn_set_input)(struct dvb_frontend *, int))
+{
+       struct mxl *state;
+       struct mxl_base *base;
+
+       state = kzalloc(sizeof(struct mxl), GFP_KERNEL);
+       if (!state)
+               return NULL;
+
+       state->demod = demod;
+       state->tuner = tuner;
+       state->tuner_in_use = 0xffffffff;
+       state->i2cdev = &i2c->dev;
+
+       base = match_base(i2c, cfg->adr);
+       if (base) {
+               base->count++;
+               if (base->count > base->demod_num)
+                       goto fail;
+               state->base = base;
+       } else {
+               base = kzalloc(sizeof(struct mxl_base), GFP_KERNEL);
+               if (!base)
+                       goto fail;
+               base->i2c = i2c;
+               base->adr = cfg->adr;
+               base->type = cfg->type;
+               base->count = 1;
+               mutex_init(&base->i2c_lock);
+               mutex_init(&base->status_lock);
+               mutex_init(&base->tune_lock);
+               INIT_LIST_HEAD(&base->mxls);
+
+               state->base = base;
+               if (probe(state, cfg) < 0) {
+                       kfree(base);
+                       goto fail;
+               }
+               list_add(&base->mxllist, &mxllist);
+       }
+       state->fe.ops               = mxl_ops;
+       state->xbar[0]              = 4;
+       state->xbar[1]              = demod;
+       state->xbar[2]              = 8;
+       state->fe.demodulator_priv  = state;
+       *fn_set_input               = set_input;
+
+       list_add(&state->mxl, &base->mxls);
+       return &state->fe;
+
+fail:
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(mxl5xx_attach);
+
+MODULE_DESCRIPTION("MaxLinear MxL5xx DVB-S/S2 tuner-demodulator driver");
+MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/mxl5xx.h b/drivers/media/dvb-frontends/mxl5xx.h
new file mode 100644 (file)
index 0000000..532e081
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef _MXL5XX_H_
+#define _MXL5XX_H_
+
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+struct mxl5xx_cfg {
+       u8   adr;
+       u8   type;
+       u32  cap;
+       u32  clk;
+       u32  ts_clk;
+
+       u8  *fw;
+       u32  fw_len;
+
+       int (*fw_read)(void *priv, u8 *buf, u32 len);
+       void *fw_priv;
+};
+
+#if IS_REACHABLE(CONFIG_DVB_MXL5XX)
+
+extern struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c,
+       struct mxl5xx_cfg *cfg, u32 demod, u32 tuner,
+       int (**fn_set_input)(struct dvb_frontend *, int));
+
+#else
+
+static inline struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c,
+       struct mxl5xx_cfg *cfg, u32 demod, u32 tuner,
+       int (**fn_set_input)(struct dvb_frontend *, int))
+{
+       pr_warn("%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+#endif /* CONFIG_DVB_MXL5XX */
+
+#endif /* _MXL5XX_H_ */
diff --git a/drivers/media/dvb-frontends/mxl5xx_defs.h b/drivers/media/dvb-frontends/mxl5xx_defs.h
new file mode 100644 (file)
index 0000000..fd9e61e
--- /dev/null
@@ -0,0 +1,731 @@
+/*
+ * Defines for the Maxlinear MX58x family of tuners/demods
+ *
+ * Copyright (C) 2014 Digital Devices GmbH
+ *
+ * based on code:
+ * Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved
+ * which was released under GPL V2
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ */
+
+enum MXL_BOOL_E {
+       MXL_DISABLE = 0,
+       MXL_ENABLE  = 1,
+
+       MXL_FALSE = 0,
+       MXL_TRUE  = 1,
+
+       MXL_INVALID = 0,
+       MXL_VALID   = 1,
+
+       MXL_NO      = 0,
+       MXL_YES     = 1,
+
+       MXL_OFF     = 0,
+       MXL_ON      = 1
+};
+
+/* Firmware-Host Command IDs */
+enum MXL_HYDRA_HOST_CMD_ID_E {
+       /* --Device command IDs-- */
+       MXL_HYDRA_DEV_NO_OP_CMD = 0, /* No OP */
+
+       MXL_HYDRA_DEV_SET_POWER_MODE_CMD = 1,
+       MXL_HYDRA_DEV_SET_OVERWRITE_DEF_CMD = 2,
+
+       /* Host-used CMD, not used by firmware */
+       MXL_HYDRA_DEV_FIRMWARE_DOWNLOAD_CMD = 3,
+
+       /* Additional CONTROL types from DTV */
+       MXL_HYDRA_DEV_SET_BROADCAST_PID_STB_ID_CMD = 4,
+       MXL_HYDRA_DEV_GET_PMM_SLEEP_CMD = 5,
+
+       /* --Tuner command IDs-- */
+       MXL_HYDRA_TUNER_TUNE_CMD = 6,
+       MXL_HYDRA_TUNER_GET_STATUS_CMD = 7,
+
+       /* --Demod command IDs-- */
+       MXL_HYDRA_DEMOD_SET_PARAM_CMD = 8,
+       MXL_HYDRA_DEMOD_GET_STATUS_CMD = 9,
+
+       MXL_HYDRA_DEMOD_RESET_FEC_COUNTER_CMD = 10,
+
+       MXL_HYDRA_DEMOD_SET_PKT_NUM_CMD = 11,
+
+       MXL_HYDRA_DEMOD_SET_IQ_SOURCE_CMD = 12,
+       MXL_HYDRA_DEMOD_GET_IQ_DATA_CMD = 13,
+
+       MXL_HYDRA_DEMOD_GET_M68HC05_VER_CMD = 14,
+
+       MXL_HYDRA_DEMOD_SET_ERROR_COUNTER_MODE_CMD = 15,
+
+       /* --- ABORT channel tune */
+       MXL_HYDRA_ABORT_TUNE_CMD = 16, /* Abort current tune command. */
+
+       /* --SWM/FSK command IDs-- */
+       MXL_HYDRA_FSK_RESET_CMD = 17,
+       MXL_HYDRA_FSK_MSG_CMD = 18,
+       MXL_HYDRA_FSK_SET_OP_MODE_CMD = 19,
+
+       /* --DiSeqC command IDs-- */
+       MXL_HYDRA_DISEQC_MSG_CMD = 20,
+       MXL_HYDRA_DISEQC_COPY_MSG_TO_MAILBOX = 21,
+       MXL_HYDRA_DISEQC_CFG_MSG_CMD = 22,
+
+       /* --- FFT Debug Command IDs-- */
+       MXL_HYDRA_REQ_FFT_SPECTRUM_CMD = 23,
+
+       /* -- Demod scramblle code */
+       MXL_HYDRA_DEMOD_SCRAMBLE_CODE_CMD = 24,
+
+       /* ---For host to know how many commands in total */
+       MXL_HYDRA_LAST_HOST_CMD = 25,
+
+       MXL_HYDRA_DEMOD_INTR_TYPE_CMD = 47,
+       MXL_HYDRA_DEV_INTR_CLEAR_CMD = 48,
+       MXL_HYDRA_TUNER_SPECTRUM_REQ_CMD = 53,
+       MXL_HYDRA_TUNER_ACTIVATE_CMD = 55,
+       MXL_HYDRA_DEV_CFG_POWER_MODE_CMD = 56,
+       MXL_HYDRA_DEV_XTAL_CAP_CMD = 57,
+       MXL_HYDRA_DEV_CFG_SKU_CMD = 58,
+       MXL_HYDRA_TUNER_SPECTRUM_MIN_GAIN_CMD = 59,
+       MXL_HYDRA_DISEQC_CONT_TONE_CFG = 60,
+       MXL_HYDRA_DEV_RF_WAKE_UP_CMD = 61,
+       MXL_HYDRA_DEMOD_CFG_EQ_CTRL_PARAM_CMD = 62,
+       MXL_HYDRA_DEMOD_FREQ_OFFSET_SEARCH_RANGE_CMD = 63,
+       MXL_HYDRA_DEV_REQ_PWR_FROM_ADCRSSI_CMD = 64,
+
+       MXL_XCPU_PID_FLT_CFG_CMD = 65,
+       MXL_XCPU_SHMEM_TEST_CMD = 66,
+       MXL_XCPU_ABORT_TUNE_CMD = 67,
+       MXL_XCPU_CHAN_TUNE_CMD = 68,
+       MXL_XCPU_FLT_BOND_HDRS_CMD = 69,
+
+       MXL_HYDRA_DEV_BROADCAST_WAKE_UP_CMD = 70,
+       MXL_HYDRA_FSK_CFG_FSK_FREQ_CMD = 71,
+       MXL_HYDRA_FSK_POWER_DOWN_CMD = 72,
+       MXL_XCPU_CLEAR_CB_STATS_CMD = 73,
+       MXL_XCPU_CHAN_BOND_RESTART_CMD = 74
+};
+
+#define MXL_ENABLE_BIG_ENDIAN        (0)
+
+#define MXL_HYDRA_OEM_MAX_BLOCK_WRITE_LENGTH   248
+
+#define MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN        (248)
+
+#define MXL_HYDRA_CAP_MIN     10
+#define MXL_HYDRA_CAP_MAX     33
+
+#define MXL_HYDRA_PLID_REG_READ       0xFB   /* Read register PLID */
+#define MXL_HYDRA_PLID_REG_WRITE      0xFC   /* Write register PLID */
+
+#define MXL_HYDRA_PLID_CMD_READ       0xFD   /* Command Read PLID */
+#define MXL_HYDRA_PLID_CMD_WRITE      0xFE   /* Command Write PLID */
+
+#define MXL_HYDRA_REG_SIZE_IN_BYTES   4      /* Hydra register size in bytes */
+#define MXL_HYDRA_I2C_HDR_SIZE        (2 * sizeof(u8)) /* PLID + LEN(0xFF) */
+#define MXL_HYDRA_CMD_HEADER_SIZE     (MXL_HYDRA_REG_SIZE_IN_BYTES + MXL_HYDRA_I2C_HDR_SIZE)
+
+#define MXL_HYDRA_SKU_ID_581 0
+#define MXL_HYDRA_SKU_ID_584 1
+#define MXL_HYDRA_SKU_ID_585 2
+#define MXL_HYDRA_SKU_ID_544 3
+#define MXL_HYDRA_SKU_ID_561 4
+#define MXL_HYDRA_SKU_ID_582 5
+#define MXL_HYDRA_SKU_ID_568 6
+
+/* macro for register write data buffer size
+ * (PLID + LEN (0xFF) + RegAddr + RegData)
+ */
+#define MXL_HYDRA_REG_WRITE_LEN       (MXL_HYDRA_I2C_HDR_SIZE + (2 * MXL_HYDRA_REG_SIZE_IN_BYTES))
+
+/* macro to extract a single byte from 4-byte(32-bit) data */
+#define GET_BYTE(x, n)  (((x) >> (8*(n))) & 0xFF)
+
+#define MAX_CMD_DATA 512
+
+#define MXL_GET_REG_MASK_32(lsb_loc, num_of_bits) ((0xFFFFFFFF >> (32 - (num_of_bits))) << (lsb_loc))
+
+#define FW_DL_SIGN (0xDEADBEEF)
+
+#define MBIN_FORMAT_VERSION               '1'
+#define MBIN_FILE_HEADER_ID               'M'
+#define MBIN_SEGMENT_HEADER_ID            'S'
+#define MBIN_MAX_FILE_LENGTH              (1<<23)
+
+struct MBIN_FILE_HEADER_T {
+       u8 id;
+       u8 fmt_version;
+       u8 header_len;
+       u8 num_segments;
+       u8 entry_address[4];
+       u8 image_size24[3];
+       u8 image_checksum;
+       u8 reserved[4];
+};
+
+struct MBIN_FILE_T {
+       struct MBIN_FILE_HEADER_T header;
+       u8 data[1];
+};
+
+struct MBIN_SEGMENT_HEADER_T {
+       u8 id;
+       u8 len24[3];
+       u8 address[4];
+};
+
+struct MBIN_SEGMENT_T {
+       struct MBIN_SEGMENT_HEADER_T header;
+       u8 data[1];
+};
+
+enum MXL_CMD_TYPE_E { MXL_CMD_WRITE = 0, MXL_CMD_READ };
+
+#define BUILD_HYDRA_CMD(cmd_id, req_type, size, data_ptr, cmd_buff)            \
+       do {                                                            \
+               cmd_buff[0] = ((req_type == MXL_CMD_WRITE) ? MXL_HYDRA_PLID_CMD_WRITE : MXL_HYDRA_PLID_CMD_READ); \
+               cmd_buff[1] = (size > 251) ? 0xff : (u8) (size + 4);    \
+               cmd_buff[2] = size;                                     \
+               cmd_buff[3] = cmd_id;                                   \
+               cmd_buff[4] = 0x00;                                     \
+               cmd_buff[5] = 0x00;                                     \
+               convert_endian(MXL_ENABLE_BIG_ENDIAN, size, (u8 *)data_ptr); \
+               memcpy((void *)&cmd_buff[6], data_ptr, size);           \
+       } while (0)
+
+struct MXL_REG_FIELD_T {
+       u32 reg_addr;
+       u8 lsb_pos;
+       u8 num_of_bits;
+};
+
+struct MXL_DEV_CMD_DATA_T {
+       u32 data_size;
+       u8 data[MAX_CMD_DATA];
+};
+
+enum MXL_HYDRA_SKU_TYPE_E {
+       MXL_HYDRA_SKU_TYPE_MIN = 0x00,
+       MXL_HYDRA_SKU_TYPE_581 = 0x00,
+       MXL_HYDRA_SKU_TYPE_584 = 0x01,
+       MXL_HYDRA_SKU_TYPE_585 = 0x02,
+       MXL_HYDRA_SKU_TYPE_544 = 0x03,
+       MXL_HYDRA_SKU_TYPE_561 = 0x04,
+       MXL_HYDRA_SKU_TYPE_5XX = 0x05,
+       MXL_HYDRA_SKU_TYPE_5YY = 0x06,
+       MXL_HYDRA_SKU_TYPE_511 = 0x07,
+       MXL_HYDRA_SKU_TYPE_561_DE = 0x08,
+       MXL_HYDRA_SKU_TYPE_582 = 0x09,
+       MXL_HYDRA_SKU_TYPE_541 = 0x0A,
+       MXL_HYDRA_SKU_TYPE_568 = 0x0B,
+       MXL_HYDRA_SKU_TYPE_542 = 0x0C,
+       MXL_HYDRA_SKU_TYPE_MAX = 0x0D,
+};
+
+struct MXL_HYDRA_SKU_COMMAND_T {
+       enum MXL_HYDRA_SKU_TYPE_E sku_type;
+};
+
+enum MXL_HYDRA_DEMOD_ID_E {
+       MXL_HYDRA_DEMOD_ID_0 = 0,
+       MXL_HYDRA_DEMOD_ID_1,
+       MXL_HYDRA_DEMOD_ID_2,
+       MXL_HYDRA_DEMOD_ID_3,
+       MXL_HYDRA_DEMOD_ID_4,
+       MXL_HYDRA_DEMOD_ID_5,
+       MXL_HYDRA_DEMOD_ID_6,
+       MXL_HYDRA_DEMOD_ID_7,
+       MXL_HYDRA_DEMOD_MAX
+};
+
+#define MXL_DEMOD_SCRAMBLE_SEQ_LEN  12
+
+#define MAX_STEP_SIZE_24_XTAL_102_05_KHZ  195
+#define MAX_STEP_SIZE_24_XTAL_204_10_KHZ  215
+#define MAX_STEP_SIZE_24_XTAL_306_15_KHZ  203
+#define MAX_STEP_SIZE_24_XTAL_408_20_KHZ  177
+
+#define MAX_STEP_SIZE_27_XTAL_102_05_KHZ  195
+#define MAX_STEP_SIZE_27_XTAL_204_10_KHZ  215
+#define MAX_STEP_SIZE_27_XTAL_306_15_KHZ  203
+#define MAX_STEP_SIZE_27_XTAL_408_20_KHZ  177
+
+#define MXL_HYDRA_SPECTRUM_MIN_FREQ_KHZ  300000
+#define MXL_HYDRA_SPECTRUM_MAX_FREQ_KHZ 2350000
+
+enum MXL_DEMOD_CHAN_PARAMS_OFFSET_E {
+       DMD_STANDARD_ADDR = 0,
+       DMD_SPECTRUM_INVERSION_ADDR,
+       DMD_SPECTRUM_ROLL_OFF_ADDR,
+       DMD_SYMBOL_RATE_ADDR,
+       DMD_MODULATION_SCHEME_ADDR,
+       DMD_FEC_CODE_RATE_ADDR,
+       DMD_SNR_ADDR,
+       DMD_FREQ_OFFSET_ADDR,
+       DMD_CTL_FREQ_OFFSET_ADDR,
+       DMD_STR_FREQ_OFFSET_ADDR,
+       DMD_FTL_FREQ_OFFSET_ADDR,
+       DMD_STR_NBC_SYNC_LOCK_ADDR,
+       DMD_CYCLE_SLIP_COUNT_ADDR,
+       DMD_DISPLAY_IQ_ADDR,
+       DMD_DVBS2_CRC_ERRORS_ADDR,
+       DMD_DVBS2_PER_COUNT_ADDR,
+       DMD_DVBS2_PER_WINDOW_ADDR,
+       DMD_DVBS_CORR_RS_ERRORS_ADDR,
+       DMD_DVBS_UNCORR_RS_ERRORS_ADDR,
+       DMD_DVBS_BER_COUNT_ADDR,
+       DMD_DVBS_BER_WINDOW_ADDR,
+       DMD_TUNER_ID_ADDR,
+       DMD_DVBS2_PILOT_ON_OFF_ADDR,
+       DMD_FREQ_SEARCH_RANGE_IN_KHZ_ADDR,
+
+       MXL_DEMOD_CHAN_PARAMS_BUFF_SIZE,
+};
+
+enum MXL_HYDRA_TUNER_ID_E {
+       MXL_HYDRA_TUNER_ID_0 = 0,
+       MXL_HYDRA_TUNER_ID_1,
+       MXL_HYDRA_TUNER_ID_2,
+       MXL_HYDRA_TUNER_ID_3,
+       MXL_HYDRA_TUNER_MAX
+};
+
+enum MXL_HYDRA_BCAST_STD_E {
+       MXL_HYDRA_DSS = 0,
+       MXL_HYDRA_DVBS,
+       MXL_HYDRA_DVBS2,
+};
+
+enum MXL_HYDRA_FEC_E {
+       MXL_HYDRA_FEC_AUTO = 0,
+       MXL_HYDRA_FEC_1_2,
+       MXL_HYDRA_FEC_3_5,
+       MXL_HYDRA_FEC_2_3,
+       MXL_HYDRA_FEC_3_4,
+       MXL_HYDRA_FEC_4_5,
+       MXL_HYDRA_FEC_5_6,
+       MXL_HYDRA_FEC_6_7,
+       MXL_HYDRA_FEC_7_8,
+       MXL_HYDRA_FEC_8_9,
+       MXL_HYDRA_FEC_9_10,
+};
+
+enum MXL_HYDRA_MODULATION_E {
+       MXL_HYDRA_MOD_AUTO = 0,
+       MXL_HYDRA_MOD_QPSK,
+       MXL_HYDRA_MOD_8PSK
+};
+
+enum MXL_HYDRA_SPECTRUM_E {
+       MXL_HYDRA_SPECTRUM_AUTO = 0,
+       MXL_HYDRA_SPECTRUM_INVERTED,
+       MXL_HYDRA_SPECTRUM_NON_INVERTED,
+};
+
+enum MXL_HYDRA_ROLLOFF_E {
+       MXL_HYDRA_ROLLOFF_AUTO  = 0,
+       MXL_HYDRA_ROLLOFF_0_20,
+       MXL_HYDRA_ROLLOFF_0_25,
+       MXL_HYDRA_ROLLOFF_0_35
+};
+
+enum MXL_HYDRA_PILOTS_E {
+       MXL_HYDRA_PILOTS_OFF  = 0,
+       MXL_HYDRA_PILOTS_ON,
+       MXL_HYDRA_PILOTS_AUTO
+};
+
+enum MXL_HYDRA_CONSTELLATION_SRC_E {
+       MXL_HYDRA_FORMATTER = 0,
+       MXL_HYDRA_LEGACY_FEC,
+       MXL_HYDRA_FREQ_RECOVERY,
+       MXL_HYDRA_NBC,
+       MXL_HYDRA_CTL,
+       MXL_HYDRA_EQ,
+};
+
+struct MXL_HYDRA_DEMOD_LOCK_T {
+       int agc_lock; /* AGC lock info */
+       int fec_lock; /* Demod FEC block lock info */
+};
+
+struct MXL_HYDRA_DEMOD_STATUS_DVBS_T {
+       u32 rs_errors;        /* RS decoder err counter */
+       u32 ber_window;       /* Ber Windows */
+       u32 ber_count;        /* BER count */
+       u32 ber_window_iter1; /* Ber Windows - post viterbi */
+       u32 ber_count_iter1;  /* BER count - post viterbi */
+};
+
+struct MXL_HYDRA_DEMOD_STATUS_DSS_T {
+       u32 rs_errors;  /* RS decoder err counter */
+       u32 ber_window; /* Ber Windows */
+       u32 ber_count;  /* BER count */
+};
+
+struct MXL_HYDRA_DEMOD_STATUS_DVBS2_T {
+       u32 crc_errors;        /* CRC error counter */
+       u32 packet_error_count; /* Number of packet errors */
+       u32 total_packets;     /* Total packets */
+};
+
+struct MXL_HYDRA_DEMOD_STATUS_T {
+       enum MXL_HYDRA_BCAST_STD_E standard_mask; /* Standard DVB-S, DVB-S2 or DSS */
+
+       union {
+               struct MXL_HYDRA_DEMOD_STATUS_DVBS_T demod_status_dvbs;   /* DVB-S demod status */
+               struct MXL_HYDRA_DEMOD_STATUS_DVBS2_T demod_status_dvbs2; /* DVB-S2 demod status */
+               struct MXL_HYDRA_DEMOD_STATUS_DSS_T demod_status_dss;     /* DSS demod status */
+       } u;
+};
+
+struct MXL_HYDRA_DEMOD_SIG_OFFSET_INFO_T {
+       s32 carrier_offset_in_hz; /* CRL offset info */
+       s32 symbol_offset_in_symbol; /* SRL offset info */
+};
+
+struct MXL_HYDRA_DEMOD_SCRAMBLE_INFO_T {
+       u8 scramble_sequence[MXL_DEMOD_SCRAMBLE_SEQ_LEN]; /* scramble sequence */
+       u32 scramble_code; /* scramble gold code */
+};
+
+enum MXL_HYDRA_SPECTRUM_STEP_SIZE_E {
+       MXL_HYDRA_STEP_SIZE_24_XTAL_102_05KHZ, /* 102.05 KHz for 24 MHz XTAL */
+       MXL_HYDRA_STEP_SIZE_24_XTAL_204_10KHZ, /* 204.10 KHz for 24 MHz XTAL */
+       MXL_HYDRA_STEP_SIZE_24_XTAL_306_15KHZ, /* 306.15 KHz for 24 MHz XTAL */
+       MXL_HYDRA_STEP_SIZE_24_XTAL_408_20KHZ, /* 408.20 KHz for 24 MHz XTAL */
+
+       MXL_HYDRA_STEP_SIZE_27_XTAL_102_05KHZ, /* 102.05 KHz for 27 MHz XTAL */
+       MXL_HYDRA_STEP_SIZE_27_XTAL_204_35KHZ, /* 204.35 KHz for 27 MHz XTAL */
+       MXL_HYDRA_STEP_SIZE_27_XTAL_306_52KHZ, /* 306.52 KHz for 27 MHz XTAL */
+       MXL_HYDRA_STEP_SIZE_27_XTAL_408_69KHZ, /* 408.69 KHz for 27 MHz XTAL */
+};
+
+enum MXL_HYDRA_SPECTRUM_RESOLUTION_E {
+       MXL_HYDRA_SPECTRUM_RESOLUTION_00_1_DB, /* 0.1 dB */
+       MXL_HYDRA_SPECTRUM_RESOLUTION_01_0_DB, /* 1.0 dB */
+       MXL_HYDRA_SPECTRUM_RESOLUTION_05_0_DB, /* 5.0 dB */
+       MXL_HYDRA_SPECTRUM_RESOLUTION_10_0_DB, /* 10 dB */
+};
+
+enum MXL_HYDRA_SPECTRUM_ERROR_CODE_E {
+       MXL_SPECTRUM_NO_ERROR,
+       MXL_SPECTRUM_INVALID_PARAMETER,
+       MXL_SPECTRUM_INVALID_STEP_SIZE,
+       MXL_SPECTRUM_BW_CANNOT_BE_COVERED,
+       MXL_SPECTRUM_DEMOD_BUSY,
+       MXL_SPECTRUM_TUNER_NOT_ENABLED,
+};
+
+struct MXL_HYDRA_SPECTRUM_REQ_T {
+       u32 tuner_index; /* TUNER Ctrl: one of MXL58x_TUNER_ID_E */
+       u32 demod_index; /* DEMOD Ctrl: one of MXL58x_DEMOD_ID_E */
+       enum MXL_HYDRA_SPECTRUM_STEP_SIZE_E step_size_in_khz;
+       u32 starting_freq_ink_hz;
+       u32 total_steps;
+       enum MXL_HYDRA_SPECTRUM_RESOLUTION_E spectrum_division;
+};
+
+enum MXL_HYDRA_SEARCH_FREQ_OFFSET_TYPE_E {
+       MXL_HYDRA_SEARCH_MAX_OFFSET = 0, /* DMD searches for max freq offset (i.e. 5MHz) */
+       MXL_HYDRA_SEARCH_BW_PLUS_ROLLOFF, /* DMD searches for BW + ROLLOFF/2 */
+};
+
+struct MXL58X_CFG_FREQ_OFF_SEARCH_RANGE_T {
+       u32 demod_index;
+       enum MXL_HYDRA_SEARCH_FREQ_OFFSET_TYPE_E search_type;
+};
+
+/* there are two slices
+ * slice0 - TS0, TS1, TS2 & TS3
+ * slice1 - TS4, TS5, TS6 & TS7
+ */
+#define MXL_HYDRA_TS_SLICE_MAX  2
+
+#define MAX_FIXED_PID_NUM   32
+
+#define MXL_HYDRA_NCO_CLK   418 /* 418 MHz */
+
+#define MXL_HYDRA_MAX_TS_CLOCK  139 /* 139 MHz */
+
+#define MXL_HYDRA_TS_FIXED_PID_FILT_SIZE          32
+
+#define MXL_HYDRA_SHARED_PID_FILT_SIZE_DEFAULT    33   /* Shared PID filter size in 1-1 mux mode */
+#define MXL_HYDRA_SHARED_PID_FILT_SIZE_2_TO_1     66   /* Shared PID filter size in 2-1 mux mode */
+#define MXL_HYDRA_SHARED_PID_FILT_SIZE_4_TO_1     132  /* Shared PID filter size in 4-1 mux mode */
+
+enum MXL_HYDRA_PID_BANK_TYPE_E {
+       MXL_HYDRA_SOFTWARE_PID_BANK = 0,
+       MXL_HYDRA_HARDWARE_PID_BANK,
+};
+
+enum MXL_HYDRA_TS_MUX_MODE_E {
+       MXL_HYDRA_TS_MUX_PID_REMAP = 0,
+       MXL_HYDRA_TS_MUX_PREFIX_EXTRA_HEADER = 1,
+};
+
+enum MXL_HYDRA_TS_MUX_TYPE_E {
+       MXL_HYDRA_TS_MUX_DISABLE = 0, /* No Mux ( 1 TSIF to 1 TSIF) */
+       MXL_HYDRA_TS_MUX_2_TO_1, /* Mux 2 TSIF to 1 TSIF */
+       MXL_HYDRA_TS_MUX_4_TO_1, /* Mux 4 TSIF to 1 TSIF */
+};
+
+enum MXL_HYDRA_TS_GROUP_E {
+       MXL_HYDRA_TS_GROUP_0_3 = 0, /* TS group 0 to 3 (TS0, TS1, TS2 & TS3) */
+       MXL_HYDRA_TS_GROUP_4_7,     /* TS group 0 to 3 (TS4, TS5, TS6 & TS7) */
+};
+
+enum MXL_HYDRA_TS_PID_FLT_CTRL_E {
+       MXL_HYDRA_TS_PIDS_ALLOW_ALL = 0, /* Allow all pids */
+       MXL_HYDRA_TS_PIDS_DROP_ALL,      /* Drop all pids */
+       MXL_HYDRA_TS_INVALIDATE_PID_FILTER, /* Delete current PD filter in the device */
+};
+
+enum MXL_HYDRA_TS_PID_TYPE_E {
+       MXL_HYDRA_TS_PID_FIXED = 0,
+       MXL_HYDRA_TS_PID_REGULAR,
+};
+
+struct MXL_HYDRA_TS_PID_T {
+       u16 original_pid;           /* pid from TS */
+       u16 remapped_pid;           /* remapped pid */
+       enum MXL_BOOL_E enable;         /* enable or disable pid */
+       enum MXL_BOOL_E allow_or_drop;    /* allow or drop pid */
+       enum MXL_BOOL_E enable_pid_remap; /* enable or disable pid remap */
+       u8 bond_id;                 /* Bond ID in A0 always 0 - Only for 568 Sku */
+       u8 dest_id;                 /* Output port ID for the PID - Only for 568 Sku */
+};
+
+struct MXL_HYDRA_TS_MUX_PREFIX_HEADER_T {
+       enum MXL_BOOL_E enable;
+       u8 num_byte;
+       u8 header[12];
+};
+
+enum MXL_HYDRA_PID_FILTER_BANK_E {
+       MXL_HYDRA_PID_BANK_A = 0,
+       MXL_HYDRA_PID_BANK_B,
+};
+
+enum MXL_HYDRA_MPEG_DATA_FMT_E {
+       MXL_HYDRA_MPEG_SERIAL_MSB_1ST = 0,
+       MXL_HYDRA_MPEG_SERIAL_LSB_1ST,
+
+       MXL_HYDRA_MPEG_SYNC_WIDTH_BIT = 0,
+       MXL_HYDRA_MPEG_SYNC_WIDTH_BYTE
+};
+
+enum MXL_HYDRA_MPEG_MODE_E {
+       MXL_HYDRA_MPEG_MODE_SERIAL_4_WIRE = 0, /* MPEG 4 Wire serial mode */
+       MXL_HYDRA_MPEG_MODE_SERIAL_3_WIRE,     /* MPEG 3 Wire serial mode */
+       MXL_HYDRA_MPEG_MODE_SERIAL_2_WIRE,     /* MPEG 2 Wire serial mode */
+       MXL_HYDRA_MPEG_MODE_PARALLEL           /* MPEG parallel mode - valid only for MxL581 */
+};
+
+enum MXL_HYDRA_MPEG_CLK_TYPE_E {
+       MXL_HYDRA_MPEG_CLK_CONTINUOUS = 0, /* Continuous MPEG clock */
+       MXL_HYDRA_MPEG_CLK_GAPPED,         /* Gapped (gated) MPEG clock */
+};
+
+enum MXL_HYDRA_MPEG_CLK_FMT_E {
+       MXL_HYDRA_MPEG_ACTIVE_LOW = 0,
+       MXL_HYDRA_MPEG_ACTIVE_HIGH,
+
+       MXL_HYDRA_MPEG_CLK_NEGATIVE = 0,
+       MXL_HYDRA_MPEG_CLK_POSITIVE,
+
+       MXL_HYDRA_MPEG_CLK_IN_PHASE = 0,
+       MXL_HYDRA_MPEG_CLK_INVERTED,
+};
+
+enum MXL_HYDRA_MPEG_CLK_PHASE_E {
+       MXL_HYDRA_MPEG_CLK_PHASE_SHIFT_0_DEG = 0,
+       MXL_HYDRA_MPEG_CLK_PHASE_SHIFT_90_DEG,
+       MXL_HYDRA_MPEG_CLK_PHASE_SHIFT_180_DEG,
+       MXL_HYDRA_MPEG_CLK_PHASE_SHIFT_270_DEG
+};
+
+enum MXL_HYDRA_MPEG_ERR_INDICATION_E {
+       MXL_HYDRA_MPEG_ERR_REPLACE_SYNC = 0,
+       MXL_HYDRA_MPEG_ERR_REPLACE_VALID,
+       MXL_HYDRA_MPEG_ERR_INDICATION_DISABLED
+};
+
+struct MXL_HYDRA_MPEGOUT_PARAM_T {
+       int                                  enable;               /* Enable or Disable MPEG OUT */
+       enum MXL_HYDRA_MPEG_CLK_TYPE_E       mpeg_clk_type;          /* Continuous or gapped */
+       enum MXL_HYDRA_MPEG_CLK_FMT_E        mpeg_clk_pol;           /* MPEG Clk polarity */
+       u8                                   max_mpeg_clk_rate;       /* Max MPEG Clk rate (0 - 104 MHz, 139 MHz) */
+       enum MXL_HYDRA_MPEG_CLK_PHASE_E      mpeg_clk_phase;         /* MPEG Clk phase */
+       enum MXL_HYDRA_MPEG_DATA_FMT_E       lsb_or_msb_first;        /* LSB first or MSB first in TS transmission */
+       enum MXL_HYDRA_MPEG_DATA_FMT_E       mpeg_sync_pulse_width;   /* MPEG SYNC pulse width (1-bit or 1-byte) */
+       enum MXL_HYDRA_MPEG_CLK_FMT_E        mpeg_valid_pol;         /* MPEG VALID polarity */
+       enum MXL_HYDRA_MPEG_CLK_FMT_E        mpeg_sync_pol;          /* MPEG SYNC polarity */
+       enum MXL_HYDRA_MPEG_MODE_E           mpeg_mode;             /* config 4/3/2-wire serial or parallel TS out */
+       enum MXL_HYDRA_MPEG_ERR_INDICATION_E mpeg_error_indication;  /* Enable or Disable MPEG error indication */
+};
+
+enum MXL_HYDRA_EXT_TS_IN_ID_E {
+       MXL_HYDRA_EXT_TS_IN_0 = 0,
+       MXL_HYDRA_EXT_TS_IN_1,
+       MXL_HYDRA_EXT_TS_IN_2,
+       MXL_HYDRA_EXT_TS_IN_3,
+       MXL_HYDRA_EXT_TS_IN_MAX
+};
+
+enum MXL_HYDRA_TS_OUT_ID_E {
+       MXL_HYDRA_TS_OUT_0 = 0,
+       MXL_HYDRA_TS_OUT_1,
+       MXL_HYDRA_TS_OUT_2,
+       MXL_HYDRA_TS_OUT_3,
+       MXL_HYDRA_TS_OUT_4,
+       MXL_HYDRA_TS_OUT_5,
+       MXL_HYDRA_TS_OUT_6,
+       MXL_HYDRA_TS_OUT_7,
+       MXL_HYDRA_TS_OUT_MAX
+};
+
+enum MXL_HYDRA_TS_DRIVE_STRENGTH_E {
+       MXL_HYDRA_TS_DRIVE_STRENGTH_1X = 0,
+       MXL_HYDRA_TS_DRIVE_STRENGTH_2X,
+       MXL_HYDRA_TS_DRIVE_STRENGTH_3X,
+       MXL_HYDRA_TS_DRIVE_STRENGTH_4X,
+       MXL_HYDRA_TS_DRIVE_STRENGTH_5X,
+       MXL_HYDRA_TS_DRIVE_STRENGTH_6X,
+       MXL_HYDRA_TS_DRIVE_STRENGTH_7X,
+       MXL_HYDRA_TS_DRIVE_STRENGTH_8X
+};
+
+enum MXL_HYDRA_DEVICE_E {
+       MXL_HYDRA_DEVICE_581 = 0,
+       MXL_HYDRA_DEVICE_584,
+       MXL_HYDRA_DEVICE_585,
+       MXL_HYDRA_DEVICE_544,
+       MXL_HYDRA_DEVICE_561,
+       MXL_HYDRA_DEVICE_TEST,
+       MXL_HYDRA_DEVICE_582,
+       MXL_HYDRA_DEVICE_541,
+       MXL_HYDRA_DEVICE_568,
+       MXL_HYDRA_DEVICE_542,
+       MXL_HYDRA_DEVICE_541S,
+       MXL_HYDRA_DEVICE_561S,
+       MXL_HYDRA_DEVICE_581S,
+       MXL_HYDRA_DEVICE_MAX
+};
+
+/* Demod IQ data */
+struct MXL_HYDRA_DEMOD_IQ_SRC_T {
+       u32 demod_id;
+       u32 source_of_iq; /* == 0, it means I/Q comes from Formatter
+                        * == 1, Legacy FEC
+                        * == 2, Frequency Recovery
+                        * == 3, NBC
+                        * == 4, CTL
+                        * == 5, EQ
+                        * == 6, FPGA
+                        */
+};
+
+struct MXL_HYDRA_DEMOD_ABORT_TUNE_T {
+       u32 demod_id;
+};
+
+struct MXL_HYDRA_TUNER_CMD {
+       u8 tuner_id;
+       u8 enable;
+};
+
+/* Demod Para for Channel Tune */
+struct MXL_HYDRA_DEMOD_PARAM_T {
+       u32 tuner_index;
+       u32 demod_index;
+       u32 frequency_in_hz;     /* Frequency */
+       u32 standard;          /* one of MXL_HYDRA_BCAST_STD_E */
+       u32 spectrum_inversion; /* Input : Spectrum inversion. */
+       u32 roll_off;           /* rollOff (alpha) factor */
+       u32 symbol_rate_in_hz;    /* Symbol rate */
+       u32 pilots;            /* TRUE = pilots enabled */
+       u32 modulation_scheme;  /* Input : Modulation Scheme is one of MXL_HYDRA_MODULATION_E */
+       u32 fec_code_rate;       /* Input : Forward error correction rate. Is one of MXL_HYDRA_FEC_E */
+       u32 max_carrier_offset_in_mhz; /* Maximum carrier freq offset in MHz. Same as freqSearchRangeKHz, but in unit of MHz. */
+};
+
+struct MXL_HYDRA_DEMOD_SCRAMBLE_CODE_T {
+       u32 demod_index;
+       u8 scramble_sequence[12]; /* scramble sequence */
+       u32 scramble_code; /* scramble gold code */
+};
+
+struct MXL_INTR_CFG_T {
+       u32 intr_type;
+       u32 intr_duration_in_nano_secs;
+       u32 intr_mask;
+};
+
+struct MXL_HYDRA_POWER_MODE_CMD {
+       u8 power_mode; /* enumeration values are defined in MXL_HYDRA_PWR_MODE_E (device API.h) */
+};
+
+struct MXL_HYDRA_RF_WAKEUP_PARAM_T {
+       u32 time_interval_in_seconds; /* in seconds */
+       u32 tuner_index;
+       s32 rssi_threshold;
+};
+
+struct MXL_HYDRA_RF_WAKEUP_CFG_T {
+       u32 tuner_count;
+       struct MXL_HYDRA_RF_WAKEUP_PARAM_T params;
+};
+
+enum MXL_HYDRA_AUX_CTRL_MODE_E {
+       MXL_HYDRA_AUX_CTRL_MODE_FSK = 0, /* Select FSK controller */
+       MXL_HYDRA_AUX_CTRL_MODE_DISEQC,  /* Select DiSEqC controller */
+};
+
+enum MXL_HYDRA_DISEQC_OPMODE_E {
+       MXL_HYDRA_DISEQC_ENVELOPE_MODE = 0,
+       MXL_HYDRA_DISEQC_TONE_MODE,
+};
+
+enum MXL_HYDRA_DISEQC_VER_E {
+       MXL_HYDRA_DISEQC_1_X = 0, /* Config DiSEqC 1.x mode */
+       MXL_HYDRA_DISEQC_2_X, /* Config DiSEqC 2.x mode */
+       MXL_HYDRA_DISEQC_DISABLE /* Disable DiSEqC */
+};
+
+enum MXL_HYDRA_DISEQC_CARRIER_FREQ_E {
+       MXL_HYDRA_DISEQC_CARRIER_FREQ_22KHZ = 0, /* DiSEqC signal frequency of 22 KHz */
+       MXL_HYDRA_DISEQC_CARRIER_FREQ_33KHZ,     /* DiSEqC signal frequency of 33 KHz */
+       MXL_HYDRA_DISEQC_CARRIER_FREQ_44KHZ      /* DiSEqC signal frequency of 44 KHz */
+};
+
+enum MXL_HYDRA_DISEQC_ID_E {
+       MXL_HYDRA_DISEQC_ID_0 = 0,
+       MXL_HYDRA_DISEQC_ID_1,
+       MXL_HYDRA_DISEQC_ID_2,
+       MXL_HYDRA_DISEQC_ID_3
+};
+
+enum MXL_HYDRA_FSK_OP_MODE_E {
+       MXL_HYDRA_FSK_CFG_TYPE_39KPBS = 0, /* 39.0kbps */
+       MXL_HYDRA_FSK_CFG_TYPE_39_017KPBS, /* 39.017kbps */
+       MXL_HYDRA_FSK_CFG_TYPE_115_2KPBS   /* 115.2kbps */
+};
+
+struct MXL58X_DSQ_OP_MODE_T {
+       u32 diseqc_id; /* DSQ 0, 1, 2 or 3 */
+       u32 op_mode; /* Envelope mode (0) or internal tone mode (1) */
+       u32 version; /* 0: 1.0, 1: 1.1, 2: Disable */
+       u32 center_freq; /* 0: 22KHz, 1: 33KHz and 2: 44 KHz */
+};
+
+struct MXL_HYDRA_DISEQC_CFG_CONT_TONE_T {
+       u32 diseqc_id;
+       u32 cont_tone_flag; /* 1: Enable , 0: Disable */
+};
diff --git a/drivers/media/dvb-frontends/mxl5xx_regs.h b/drivers/media/dvb-frontends/mxl5xx_regs.h
new file mode 100644 (file)
index 0000000..5001daf
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved
+ *
+ * License type: GPLv2
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * This program may alternatively be licensed under a proprietary license from
+ * MaxLinear, Inc.
+ *
+ */
+
+#ifndef __MXL58X_REGISTERS_H__
+#define __MXL58X_REGISTERS_H__
+
+#define HYDRA_INTR_STATUS_REG               0x80030008
+#define HYDRA_INTR_MASK_REG                 0x8003000C
+
+#define HYDRA_CRYSTAL_SETTING               0x3FFFC5F0 /* 0 - 24 MHz & 1 - 27 MHz */
+#define HYDRA_CRYSTAL_CAP                   0x3FFFEDA4 /* 0 - 24 MHz & 1 - 27 MHz */
+
+#define HYDRA_CPU_RESET_REG                 0x8003003C
+#define HYDRA_CPU_RESET_DATA                0x00000400
+
+#define HYDRA_RESET_TRANSPORT_FIFO_REG      0x80030028
+#define HYDRA_RESET_TRANSPORT_FIFO_DATA     0x00000000
+
+#define HYDRA_RESET_BBAND_REG               0x80030024
+#define HYDRA_RESET_BBAND_DATA              0x00000000
+
+#define HYDRA_RESET_XBAR_REG                0x80030020
+#define HYDRA_RESET_XBAR_DATA               0x00000000
+
+#define HYDRA_MODULES_CLK_1_REG             0x80030014
+#define HYDRA_DISABLE_CLK_1                 0x00000000
+
+#define HYDRA_MODULES_CLK_2_REG             0x8003001C
+#define HYDRA_DISABLE_CLK_2                 0x0000000B
+
+#define HYDRA_PRCM_ROOT_CLK_REG             0x80030018
+#define HYDRA_PRCM_ROOT_CLK_DISABLE         0x00000000
+
+#define HYDRA_CPU_RESET_CHECK_REG           0x80030008
+#define HYDRA_CPU_RESET_CHECK_OFFSET        0x40000000  /* <bit 30> */
+
+#define HYDRA_SKU_ID_REG                    0x90000190
+
+#define FW_DL_SIGN_ADDR                     0x3FFFEAE0
+
+/* Register to check if FW is running or not */
+#define HYDRA_HEAR_BEAT                     0x3FFFEDDC
+
+/* Firmware version */
+#define HYDRA_FIRMWARE_VERSION              0x3FFFEDB8
+#define HYDRA_FW_RC_VERSION                 0x3FFFCFAC
+
+/* Firmware patch version */
+#define HYDRA_FIRMWARE_PATCH_VERSION        0x3FFFEDC2
+
+/* SOC operating temperature in C */
+#define HYDRA_TEMPARATURE                   0x3FFFEDB4
+
+/* Demod & Tuner status registers */
+/* Demod 0 status base address */
+#define HYDRA_DEMOD_0_BASE_ADDR             0x3FFFC64C
+
+/* Tuner 0 status base address */
+#define HYDRA_TUNER_0_BASE_ADDR             0x3FFFCE4C
+
+#define POWER_FROM_ADCRSSI_READBACK         0x3FFFEB6C
+
+/* Macros to determine base address of respective demod or tuner */
+#define HYDRA_DMD_STATUS_OFFSET(demodID)        ((demodID) * 0x100)
+#define HYDRA_TUNER_STATUS_OFFSET(tunerID)      ((tunerID) * 0x40)
+
+/* Demod status address offset from respective demod's base address */
+#define HYDRA_DMD_AGC_DIG_LEVEL_ADDR_OFFSET               0x3FFFC64C
+#define HYDRA_DMD_LOCK_STATUS_ADDR_OFFSET                 0x3FFFC650
+#define HYDRA_DMD_ACQ_STATUS_ADDR_OFFSET                  0x3FFFC654
+
+#define HYDRA_DMD_STANDARD_ADDR_OFFSET                    0x3FFFC658
+#define HYDRA_DMD_SPECTRUM_INVERSION_ADDR_OFFSET          0x3FFFC65C
+#define HYDRA_DMD_SPECTRUM_ROLL_OFF_ADDR_OFFSET           0x3FFFC660
+#define HYDRA_DMD_SYMBOL_RATE_ADDR_OFFSET                 0x3FFFC664
+#define HYDRA_DMD_MODULATION_SCHEME_ADDR_OFFSET           0x3FFFC668
+#define HYDRA_DMD_FEC_CODE_RATE_ADDR_OFFSET               0x3FFFC66C
+
+#define HYDRA_DMD_SNR_ADDR_OFFSET                         0x3FFFC670
+#define HYDRA_DMD_FREQ_OFFSET_ADDR_OFFSET                 0x3FFFC674
+#define HYDRA_DMD_CTL_FREQ_OFFSET_ADDR_OFFSET             0x3FFFC678
+#define HYDRA_DMD_STR_FREQ_OFFSET_ADDR_OFFSET             0x3FFFC67C
+#define HYDRA_DMD_FTL_FREQ_OFFSET_ADDR_OFFSET             0x3FFFC680
+#define HYDRA_DMD_STR_NBC_SYNC_LOCK_ADDR_OFFSET           0x3FFFC684
+#define HYDRA_DMD_CYCLE_SLIP_COUNT_ADDR_OFFSET            0x3FFFC688
+
+#define HYDRA_DMD_DISPLAY_I_ADDR_OFFSET                   0x3FFFC68C
+#define HYDRA_DMD_DISPLAY_Q_ADDR_OFFSET                   0x3FFFC68E
+
+#define HYDRA_DMD_DVBS2_CRC_ERRORS_ADDR_OFFSET            0x3FFFC690
+#define HYDRA_DMD_DVBS2_PER_COUNT_ADDR_OFFSET             0x3FFFC694
+#define HYDRA_DMD_DVBS2_PER_WINDOW_ADDR_OFFSET            0x3FFFC698
+
+#define HYDRA_DMD_DVBS_CORR_RS_ERRORS_ADDR_OFFSET         0x3FFFC69C
+#define HYDRA_DMD_DVBS_UNCORR_RS_ERRORS_ADDR_OFFSET       0x3FFFC6A0
+#define HYDRA_DMD_DVBS_BER_COUNT_ADDR_OFFSET              0x3FFFC6A4
+#define HYDRA_DMD_DVBS_BER_WINDOW_ADDR_OFFSET             0x3FFFC6A8
+
+/* Debug-purpose DVB-S DMD 0 */
+#define HYDRA_DMD_DVBS_1ST_CORR_RS_ERRORS_ADDR_OFFSET     0x3FFFC6C8  /* corrected RS Errors: 1st iteration */
+#define HYDRA_DMD_DVBS_1ST_UNCORR_RS_ERRORS_ADDR_OFFSET   0x3FFFC6CC  /* uncorrected RS Errors: 1st iteration */
+#define HYDRA_DMD_DVBS_BER_COUNT_1ST_ADDR_OFFSET          0x3FFFC6D0
+#define HYDRA_DMD_DVBS_BER_WINDOW_1ST_ADDR_OFFSET         0x3FFFC6D4
+
+#define HYDRA_DMD_TUNER_ID_ADDR_OFFSET                    0x3FFFC6AC
+#define HYDRA_DMD_DVBS2_PILOT_ON_OFF_ADDR_OFFSET          0x3FFFC6B0
+#define HYDRA_DMD_FREQ_SEARCH_RANGE_KHZ_ADDR_OFFSET       0x3FFFC6B4
+#define HYDRA_DMD_STATUS_LOCK_ADDR_OFFSET                 0x3FFFC6B8
+#define HYDRA_DMD_STATUS_CENTER_FREQ_IN_KHZ_ADDR          0x3FFFC704
+#define HYDRA_DMD_STATUS_INPUT_POWER_ADDR                 0x3FFFC708
+
+/* DVB-S new scaled_BER_count for a new BER API, see HYDRA-1343 "DVB-S post viterbi information" */
+#define DMD0_STATUS_DVBS_1ST_SCALED_BER_COUNT_ADDR        0x3FFFC710 /* DMD 0: 1st iteration BER count scaled by HYDRA_BER_COUNT_SCALING_FACTOR */
+#define DMD0_STATUS_DVBS_SCALED_BER_COUNT_ADDR            0x3FFFC714 /* DMD 0: 2nd iteration BER count scaled by HYDRA_BER_COUNT_SCALING_FACTOR */
+
+#define DMD0_SPECTRUM_MIN_GAIN_STATUS                     0x3FFFC73C
+#define DMD0_SPECTRUM_MIN_GAIN_WB_SAGC_VALUE              0x3FFFC740
+#define DMD0_SPECTRUM_MIN_GAIN_NB_SAGC_VALUE              0x3FFFC744
+
+#define HYDRA_DMD_STATUS_END_ADDR_OFFSET                  0x3FFFC748
+
+/* Tuner status address offset from respective tuners's base address */
+#define HYDRA_TUNER_DEMOD_ID_ADDR_OFFSET                  0x3FFFCE4C
+#define HYDRA_TUNER_AGC_LOCK_OFFSET                       0x3FFFCE50
+#define HYDRA_TUNER_SPECTRUM_STATUS_OFFSET                0x3FFFCE54
+#define HYDRA_TUNER_SPECTRUM_BIN_SIZE_OFFSET              0x3FFFCE58
+#define HYDRA_TUNER_SPECTRUM_ADDRESS_OFFSET               0x3FFFCE5C
+#define HYDRA_TUNER_ENABLE_COMPLETE                       0x3FFFEB78
+
+#define HYDRA_DEMOD_STATUS_LOCK(devId, demodId)   write_register(devId, (HYDRA_DMD_STATUS_LOCK_ADDR_OFFSET + HYDRA_DMD_STATUS_OFFSET(demodId)), MXL_YES)
+#define HYDRA_DEMOD_STATUS_UNLOCK(devId, demodId) write_register(devId, (HYDRA_DMD_STATUS_LOCK_ADDR_OFFSET + HYDRA_DMD_STATUS_OFFSET(demodId)), MXL_NO)
+
+#define HYDRA_VERSION                                     0x3FFFEDB8
+#define HYDRA_DEMOD0_VERSION                              0x3FFFEDBC
+#define HYDRA_DEMOD1_VERSION                              0x3FFFEDC0
+#define HYDRA_DEMOD2_VERSION                              0x3FFFEDC4
+#define HYDRA_DEMOD3_VERSION                              0x3FFFEDC8
+#define HYDRA_DEMOD4_VERSION                              0x3FFFEDCC
+#define HYDRA_DEMOD5_VERSION                              0x3FFFEDD0
+#define HYDRA_DEMOD6_VERSION                              0x3FFFEDD4
+#define HYDRA_DEMOD7_VERSION                              0x3FFFEDD8
+#define HYDRA_HEAR_BEAT                                   0x3FFFEDDC
+#define HYDRA_SKU_MGMT                                    0x3FFFEBC0
+
+#define MXL_HYDRA_FPGA_A_ADDRESS                          0x91C00000
+#define MXL_HYDRA_FPGA_B_ADDRESS                          0x91D00000
+
+/* TS control base address */
+#define HYDRA_TS_CTRL_BASE_ADDR                           0x90700000
+
+#define MPEG_MUX_MODE_SLICE0_REG            (HYDRA_TS_CTRL_BASE_ADDR + 0x08)
+
+#define MPEG_MUX_MODE_SLICE1_REG            (HYDRA_TS_CTRL_BASE_ADDR + 0x08)
+
+#define PID_BANK_SEL_SLICE0_REG             (HYDRA_TS_CTRL_BASE_ADDR + 0x190)
+#define PID_BANK_SEL_SLICE1_REG             (HYDRA_TS_CTRL_BASE_ADDR + 0x1B0)
+
+#define MPEG_CLK_GATED_REG                  (HYDRA_TS_CTRL_BASE_ADDR + 0x20)
+
+#define MPEG_CLK_ALWAYS_ON_REG              (HYDRA_TS_CTRL_BASE_ADDR + 0x1D4)
+
+#define HYDRA_REGULAR_PID_BANK_A_REG        (HYDRA_TS_CTRL_BASE_ADDR + 0x190)
+
+#define HYDRA_FIXED_PID_BANK_A_REG          (HYDRA_TS_CTRL_BASE_ADDR + 0x190)
+
+#define HYDRA_REGULAR_PID_BANK_B_REG        (HYDRA_TS_CTRL_BASE_ADDR + 0x1B0)
+
+#define HYDRA_FIXED_PID_BANK_B_REG          (HYDRA_TS_CTRL_BASE_ADDR + 0x1B0)
+
+#define FIXED_PID_TBL_REG_ADDRESS_0         (HYDRA_TS_CTRL_BASE_ADDR + 0x9000)
+#define FIXED_PID_TBL_REG_ADDRESS_1         (HYDRA_TS_CTRL_BASE_ADDR + 0x9100)
+#define FIXED_PID_TBL_REG_ADDRESS_2         (HYDRA_TS_CTRL_BASE_ADDR + 0x9200)
+#define FIXED_PID_TBL_REG_ADDRESS_3         (HYDRA_TS_CTRL_BASE_ADDR + 0x9300)
+
+#define FIXED_PID_TBL_REG_ADDRESS_4         (HYDRA_TS_CTRL_BASE_ADDR + 0xB000)
+#define FIXED_PID_TBL_REG_ADDRESS_5         (HYDRA_TS_CTRL_BASE_ADDR + 0xB100)
+#define FIXED_PID_TBL_REG_ADDRESS_6         (HYDRA_TS_CTRL_BASE_ADDR + 0xB200)
+#define FIXED_PID_TBL_REG_ADDRESS_7         (HYDRA_TS_CTRL_BASE_ADDR + 0xB300)
+
+#define REGULAR_PID_TBL_REG_ADDRESS_0       (HYDRA_TS_CTRL_BASE_ADDR + 0x8000)
+#define REGULAR_PID_TBL_REG_ADDRESS_1       (HYDRA_TS_CTRL_BASE_ADDR + 0x8200)
+#define REGULAR_PID_TBL_REG_ADDRESS_2       (HYDRA_TS_CTRL_BASE_ADDR + 0x8400)
+#define REGULAR_PID_TBL_REG_ADDRESS_3       (HYDRA_TS_CTRL_BASE_ADDR + 0x8600)
+
+#define REGULAR_PID_TBL_REG_ADDRESS_4       (HYDRA_TS_CTRL_BASE_ADDR + 0xA000)
+#define REGULAR_PID_TBL_REG_ADDRESS_5       (HYDRA_TS_CTRL_BASE_ADDR + 0xA200)
+#define REGULAR_PID_TBL_REG_ADDRESS_6       (HYDRA_TS_CTRL_BASE_ADDR + 0xA400)
+#define REGULAR_PID_TBL_REG_ADDRESS_7       (HYDRA_TS_CTRL_BASE_ADDR + 0xA600)
+
+/***************************************************************************/
+
+#define PAD_MUX_GPIO_00_SYNC_BASEADDR                          0x90000188
+
+
+#define PAD_MUX_UART_RX_C_PINMUX_BASEADDR 0x9000001C
+
+#define   XPT_PACKET_GAP_MIN_BASEADDR                            0x90700044
+#define   XPT_NCO_COUNT_BASEADDR                                 0x90700238
+
+#define   XPT_NCO_COUNT_BASEADDR1                                0x9070023C
+
+/* V2 DigRF status register */
+
+#define   XPT_PID_BASEADDR                                       0x90708000
+
+#define   XPT_PID_REMAP_BASEADDR                                 0x90708004
+
+#define   XPT_KNOWN_PID_BASEADDR                                 0x90709000
+
+#define   XPT_PID_BASEADDR1                                      0x9070A000
+
+#define   XPT_PID_REMAP_BASEADDR1                                0x9070A004
+
+#define   XPT_KNOWN_PID_BASEADDR1                                0x9070B000
+
+#define   XPT_BERT_LOCK_BASEADDR                                 0x907000B8
+
+#define   XPT_BERT_BASEADDR                                      0x907000BC
+
+#define   XPT_BERT_INVERT_BASEADDR                               0x907000C0
+
+#define   XPT_BERT_HEADER_BASEADDR                               0x907000C4
+
+#define   XPT_BERT_BASEADDR1                                     0x907000C8
+
+#define   XPT_BERT_BIT_COUNT0_BASEADDR                           0x907000CC
+
+#define   XPT_BERT_BIT_COUNT0_BASEADDR1                          0x907000D0
+
+#define   XPT_BERT_BIT_COUNT1_BASEADDR                           0x907000D4
+
+#define   XPT_BERT_BIT_COUNT1_BASEADDR1                          0x907000D8
+
+#define   XPT_BERT_BIT_COUNT2_BASEADDR                           0x907000DC
+
+#define   XPT_BERT_BIT_COUNT2_BASEADDR1                          0x907000E0
+
+#define   XPT_BERT_BIT_COUNT3_BASEADDR                           0x907000E4
+
+#define   XPT_BERT_BIT_COUNT3_BASEADDR1                          0x907000E8
+
+#define   XPT_BERT_BIT_COUNT4_BASEADDR                           0x907000EC
+
+#define   XPT_BERT_BIT_COUNT4_BASEADDR1                          0x907000F0
+
+#define   XPT_BERT_BIT_COUNT5_BASEADDR                           0x907000F4
+
+#define   XPT_BERT_BIT_COUNT5_BASEADDR1                          0x907000F8
+
+#define   XPT_BERT_BIT_COUNT6_BASEADDR                           0x907000FC
+
+#define   XPT_BERT_BIT_COUNT6_BASEADDR1                          0x90700100
+
+#define   XPT_BERT_BIT_COUNT7_BASEADDR                           0x90700104
+
+#define   XPT_BERT_BIT_COUNT7_BASEADDR1                          0x90700108
+
+#define   XPT_BERT_ERR_COUNT0_BASEADDR                           0x9070010C
+
+#define   XPT_BERT_ERR_COUNT0_BASEADDR1                          0x90700110
+
+#define   XPT_BERT_ERR_COUNT1_BASEADDR                           0x90700114
+
+#define   XPT_BERT_ERR_COUNT1_BASEADDR1                          0x90700118
+
+#define   XPT_BERT_ERR_COUNT2_BASEADDR                           0x9070011C
+
+#define   XPT_BERT_ERR_COUNT2_BASEADDR1                          0x90700120
+
+#define   XPT_BERT_ERR_COUNT3_BASEADDR                           0x90700124
+
+#define   XPT_BERT_ERR_COUNT3_BASEADDR1                          0x90700128
+
+#define   XPT_BERT_ERR_COUNT4_BASEADDR                           0x9070012C
+
+#define   XPT_BERT_ERR_COUNT4_BASEADDR1                          0x90700130
+
+#define   XPT_BERT_ERR_COUNT5_BASEADDR                           0x90700134
+
+#define   XPT_BERT_ERR_COUNT5_BASEADDR1                          0x90700138
+
+#define   XPT_BERT_ERR_COUNT6_BASEADDR                           0x9070013C
+
+#define   XPT_BERT_ERR_COUNT6_BASEADDR1                          0x90700140
+
+#define   XPT_BERT_ERR_COUNT7_BASEADDR                           0x90700144
+
+#define   XPT_BERT_ERR_COUNT7_BASEADDR1                          0x90700148
+
+#define   XPT_BERT_ERROR_BASEADDR                                0x9070014C
+
+#define   XPT_BERT_ANALYZER_BASEADDR                             0x90700150
+
+#define   XPT_BERT_ANALYZER_BASEADDR1                            0x90700154
+
+#define   XPT_BERT_ANALYZER_BASEADDR2                            0x90700158
+
+#define   XPT_BERT_ANALYZER_BASEADDR3                            0x9070015C
+
+#define   XPT_BERT_ANALYZER_BASEADDR4                            0x90700160
+
+#define   XPT_BERT_ANALYZER_BASEADDR5                            0x90700164
+
+#define   XPT_BERT_ANALYZER_BASEADDR6                            0x90700168
+
+#define   XPT_BERT_ANALYZER_BASEADDR7                            0x9070016C
+
+#define   XPT_BERT_ANALYZER_BASEADDR8                            0x90700170
+
+#define   XPT_BERT_ANALYZER_BASEADDR9                            0x90700174
+
+#define   XPT_DMD0_BASEADDR                                      0x9070024C
+
+/* V2 AGC Gain Freeze & step */
+#define   DBG_ENABLE_DISABLE_AGC                                 (0x3FFFCF60) /* 1: DISABLE, 0:ENABLE */
+#define   WB_DFE0_DFE_FB_RF1_BASEADDR                            0x903004A4
+
+#define   WB_DFE1_DFE_FB_RF1_BASEADDR                            0x904004A4
+
+#define   WB_DFE2_DFE_FB_RF1_BASEADDR                            0x905004A4
+
+#define   WB_DFE3_DFE_FB_RF1_BASEADDR                            0x906004A4
+
+#define   AFE_REG_D2A_TA_RFFE_LNA_BO_1P8_BASEADDR                0x90200104
+
+#define   AFE_REG_AFE_REG_SPARE_BASEADDR                         0x902000A0
+
+#define   AFE_REG_AFE_REG_SPARE_BASEADDR1                        0x902000B4
+
+#define   AFE_REG_AFE_REG_SPARE_BASEADDR2                        0x902000C4
+
+#define   AFE_REG_AFE_REG_SPARE_BASEADDR3                        0x902000D4
+
+#define   WB_DFE0_DFE_FB_AGC_BASEADDR                            0x90300498
+
+#define   WB_DFE1_DFE_FB_AGC_BASEADDR                            0x90400498
+
+#define   WB_DFE2_DFE_FB_AGC_BASEADDR                            0x90500498
+
+#define   WB_DFE3_DFE_FB_AGC_BASEADDR                            0x90600498
+
+#define   WDT_WD_INT_BASEADDR                                    0x8002000C
+
+#define   FSK_TX_FTM_BASEADDR                                    0x80090000
+
+#define   FSK_TX_FTM_TX_CNT_BASEADDR                             0x80090018
+
+#define   AFE_REG_D2A_FSK_BIAS_BASEADDR                          0x90200040
+
+#define   DMD_TEI_BASEADDR                                       0x3FFFEBE0
+
+#endif /* __MXL58X_REGISTERS_H__ */