Added support for the CXD2843ER demodulator for DVB-T/T2/C/C2
used by recent Digital Devices hardware.

Signed-off-by: Maik Broemme <mbroe...@parallels.com>
---
 drivers/media/dvb-frontends/Kconfig   |    9 +
 drivers/media/dvb-frontends/Makefile  |    1 +
 drivers/media/dvb-frontends/cxd2843.c | 1647 +++++++++++++++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2843.h |   47 +
 4 files changed, 1704 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2843.c
 create mode 100644 drivers/media/dvb-frontends/cxd2843.h

diff --git a/drivers/media/dvb-frontends/Kconfig 
b/drivers/media/dvb-frontends/Kconfig
index a34c1c7..3e39319 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -74,6 +74,15 @@ config DVB_TDA18212DD
 
          Say Y when you want to support this tuner.
 
+config DVB_CXD2843
+       tristate "CXD2843ER based for DVB-T/T2/C/C2"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         Sony CXD2843ER/CXD2837ER DVB-T/T2/C/C2 demodulator.
+
+         Say Y when you want to support this frontend.
+
 comment "DVB-S (satellite) frontends"
        depends on DVB_CORE
 
diff --git a/drivers/media/dvb-frontends/Makefile 
b/drivers/media/dvb-frontends/Makefile
index ed12424..90cad36 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -99,6 +99,7 @@ obj-$(CONFIG_DVB_DRXK) += drxk.o
 obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
 obj-$(CONFIG_DVB_STV0367DD) += stv0367dd.o
 obj-$(CONFIG_DVB_TDA18212DD) += tda18212dd.o
+obj-$(CONFIG_DVB_CXD2843) += cxd2843.o
 obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o
 obj-$(CONFIG_DVB_A8293) += a8293.o
 obj-$(CONFIG_DVB_TDA10071) += tda10071.o
diff --git a/drivers/media/dvb-frontends/cxd2843.c 
b/drivers/media/dvb-frontends/cxd2843.c
new file mode 100644
index 0000000..87a3000
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2843.c
@@ -0,0 +1,1647 @@
+/*
+ *  cxd2843.c: Driver for the Sony CXD2843ER DVB-T/T2/C/C2 demodulator.
+ *             Also supports the CXD2837ER DVB-T/T2/C and the CXD2838ER
+ *             ISDB-T demodulator.
+ *
+ *  Copyright (C) 2010-2013 Digital Devices GmbH
+ *  Copyright (C) 2013 Maik Broemme <mbroe...@parallels.com>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  version 2 only, 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA
+ */
+
+#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 <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "cxd2843.h"
+
+
+enum EDemodType { CXD2843, CXD2837, CXD2838 };
+enum EDemodState { Unknown, Shutdown, Sleep, ActiveT, ActiveT2, ActiveC, 
ActiveC2, ActiveIT };
+enum omode { OM_NONE, OM_DVBT, OM_DVBT2, OM_DVBC, OM_QAM_ITU_C, OM_DVBC2, 
OM_ISDBT };
+
+struct cxd_state {
+       struct dvb_frontend   frontend;
+       struct i2c_adapter   *i2c;
+       struct mutex          mutex;
+
+       u8  adrt;
+       u8  curbankt;
+
+       u8  adrx;
+       u8  curbankx;
+
+       enum EDemodType  type;
+       enum EDemodState state;
+       enum omode omode;
+
+       u8    IF_FS;
+       int   ContinuousClock;
+       int   SerialMode;
+       u8    SerialClockFrequency;
+       
+       u32   LockTimeout;
+       u32   TSLockTimeout;
+       u32   L1PostTimeout;
+       u32   DataSliceID;      
+       int   FirstTimeLock;
+       u32   PLPNumber;
+       u32   last_status;
+       
+       u32 bandwidth;
+       u32 bw;
+};
+
+static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
+{
+       struct i2c_msg msg =
+               {.addr = adr, .flags = 0, .buf = data, .len = len};
+
+       if (i2c_transfer(adap, &msg, 1) != 1) {
+               printk("cxd2843: i2c_write error\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int writeregs(struct cxd_state *state, u8 adr, u8 reg, u8 *regd, u16 
len)
+{
+       u8 data[len + 1];
+
+       data[0] = reg;
+       memcpy(data + 1, regd, len);
+       return i2c_write(state->i2c, adr, data, len + 1);
+}
+
+static int writereg(struct cxd_state *state, u8 adr, u8 reg, u8 dat)
+{
+       u8 mm[2] = {reg, dat};
+
+       return i2c_write(state->i2c, adr, mm, 2);
+}
+
+static int i2c_read(struct i2c_adapter *adap,
+                   u8 adr, u8 *msg, int len, u8 *answ, int alen)
+{
+       struct i2c_msg msgs[2] = { { .addr = adr, .flags = 0,
+                                    .buf = msg, .len = len},
+                                  { .addr = adr, .flags = I2C_M_RD,
+                                    .buf = answ, .len = alen } };
+       if (i2c_transfer(adap, msgs, 2) != 2) {
+               printk("cxd2843: i2c_read error\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int readregs(struct cxd_state *state, u8 adr, u8 reg, u8 *val, int 
count)
+{
+       return i2c_read(state->i2c, adr, &reg, 1, val, count); 
+}
+
+static int readregst_unlocked(struct cxd_state *cxd, u8 bank, u8 Address, u8 
*pValue, u16 count)
+{
+       int status = 0;
+       
+       if (bank != 0xFF && cxd->curbankt != bank) {
+               status = writereg(cxd, cxd->adrt, 0, bank);
+               if (status < 0) {
+                       cxd->curbankt = 0xFF;
+                       return status;
+               }
+               cxd->curbankt = bank;
+       }
+       status = readregs(cxd, cxd->adrt, Address, pValue, count);
+       return status;
+}
+
+static int readregst(struct cxd_state *cxd, u8 Bank, u8 Address, u8 *pValue, 
u16 count)
+{
+       int status;
+       
+       mutex_lock(&cxd->mutex);
+       status = readregst_unlocked(cxd, Bank, Address, pValue, count);
+       mutex_unlock(&cxd->mutex);
+       return status;
+}
+
+static int readregsx_unlocked(struct cxd_state *cxd, u8 Bank, u8 Address, u8 
*pValue, u16 count)
+{
+       int status = 0;
+       
+       if (Bank != 0xFF && cxd->curbankx != Bank) {
+               status = writereg(cxd, cxd->adrx, 0, Bank);
+               if (status < 0) {
+                       cxd->curbankx = 0xFF;
+                       return status;
+               }
+               cxd->curbankx = Bank;
+       }
+       status = readregs(cxd, cxd->adrx, Address, pValue, count);
+       return status;
+}
+
+static int readregsx(struct cxd_state *cxd, u8 Bank, u8 Address, u8 *pValue, 
u16 count)
+{
+       int status;
+       
+       mutex_lock(&cxd->mutex);
+       status = readregsx_unlocked(cxd, Bank, Address, pValue, count);
+       mutex_unlock(&cxd->mutex);
+       return status;
+}
+
+static int writeregsx_unlocked(struct cxd_state *cxd, u8 Bank, u8 Address, u8 
*pValue, u16 count)
+{
+       int status = 0;
+       
+       if (Bank != 0xFF && cxd->curbankx != Bank) {
+               status = writereg(cxd, cxd->adrx, 0, Bank);
+               if (status < 0) {
+                       cxd->curbankx = 0xFF;
+                       return status;
+               }
+               cxd->curbankx = Bank;
+       }
+       status = writeregs(cxd, cxd->adrx, Address, pValue, count);
+       return status;
+}
+
+static int writeregsx(struct cxd_state *cxd, u8 Bank, u8 Address, u8 *pValue, 
u16 count)
+{
+       int status;
+       
+       mutex_lock(&cxd->mutex);
+       status = writeregsx_unlocked(cxd, Bank, Address, pValue, count);
+       mutex_unlock(&cxd->mutex);
+       return status;
+}
+
+static int writeregx(struct cxd_state *cxd, u8 Bank, u8 Address, u8 val)
+{
+       return writeregsx(cxd, Bank, Address, &val, 1);
+}
+
+static int writeregst_unlocked(struct cxd_state *cxd, u8 Bank, u8 Address, u8 
*pValue, u16 count)
+{
+       int status = 0;
+       
+       if (Bank != 0xFF && cxd->curbankt != Bank) {
+               status = writereg(cxd, cxd->adrt, 0, Bank);
+               if (status < 0) {
+                       cxd->curbankt = 0xFF;
+                       return status;
+               }
+               cxd->curbankt = Bank;
+       }
+       status = writeregs(cxd, cxd->adrt, Address, pValue, count);
+       return status;
+}
+
+static int writeregst(struct cxd_state *cxd, u8 Bank, u8 Address, u8 *pValue, 
u16 count)
+{
+       int status;
+       
+       mutex_lock(&cxd->mutex);
+       status = writeregst_unlocked(cxd, Bank, Address, pValue, count);
+       mutex_unlock(&cxd->mutex);
+       return status;
+}
+
+static int writeregt(struct cxd_state *cxd, u8 Bank, u8 Address, u8 val)
+{
+       return writeregst(cxd, Bank, Address, &val, 1);
+}
+
+static int writebitsx(struct cxd_state *cxd, u8 Bank, u8 Address, u8 Value, u8 
Mask)
+{
+       int status = 0;
+       u8 tmp;
+
+       mutex_lock(&cxd->mutex);
+       status = readregsx_unlocked(cxd, Bank, Address, &tmp, 1);
+       if (status < 0) 
+               return status;
+       tmp = (tmp & ~Mask) | Value;
+       status = writeregsx_unlocked(cxd, Bank, Address, &tmp, 1);
+       mutex_unlock(&cxd->mutex);
+       return status;
+}
+
+static int writebitst(struct cxd_state *cxd, u8 Bank, u8 Address, u8 Value, u8 
Mask)
+{
+       int status = 0;
+       u8 Tmp = 0x00;
+
+       mutex_lock(&cxd->mutex);
+       status = readregst_unlocked(cxd, Bank, Address, &Tmp, 1);
+       if (status < 0) 
+               return status;
+       Tmp = (Tmp & ~Mask) | Value;
+       status = writeregst_unlocked(cxd, Bank, Address, &Tmp, 1);
+       mutex_unlock(&cxd->mutex);
+       return status;
+}
+
+static int FreezeRegsT(struct cxd_state *cxd)
+{
+       mutex_lock(&cxd->mutex);
+       return writereg(cxd, cxd->adrt, 1, 1);
+}
+
+static int UnFreezeRegsT(struct cxd_state *cxd)
+{
+       int status = 0;
+
+       status = writereg(cxd, cxd->adrt, 1, 0);
+       mutex_unlock(&cxd->mutex);
+       return status;
+}
+
+static inline u32 MulDiv32(u32 a, u32 b, u32 c)
+{
+       u64 tmp64;
+
+       tmp64 = (u64)a * (u64)b;
+       do_div(tmp64, c);
+
+       return (u32) tmp64;
+}
+
+static void Active_to_Sleep(struct cxd_state *state)
+{
+       if (state->state <= Sleep ) 
+               return;
+
+       writeregt(state, 0x00,0xC3,0x01);   // Disable TS
+        writeregt(state, 0x00,0x80,0x3F);   // Enable HighZ 1
+        writeregt(state, 0x00,0x81,0xFF);   // Enable HighZ 2
+        writeregx(state, 0x00,0x18,0x01);   // Disable ADC 4
+        writeregt(state, 0x00,0x43,0x0A);   // Disable ADC 2 // This looks 
broken (see enable)
+        writeregt(state, 0x00,0x41,0x0A);   // Disable ADC 1
+        writeregt(state, 0x00,0x30,0x00);   // Disable ADC Clock
+        writeregt(state, 0x00,0x2F,0x00);   // Disable RF level Monitor
+        writeregt(state, 0x00,0x2C,0x00);   // Disable Demod Clock
+       state->state = Sleep;
+}
+
+static void ActiveT2_to_Sleep(struct cxd_state *state)
+{
+       if (state->state <= Sleep ) 
+               return;
+       
+        writeregt(state, 0x00,0xC3,0x01);   // Disable TS
+       writeregt(state, 0x00,0x80,0x3F);   // Enable HighZ 1
+        writeregt(state, 0x00,0x81,0xFF);   // Enable HighZ 2
+       
+        writeregt(state, 0x13,0x83,0x40);   //
+        writeregt(state, 0x13,0x86,0x21);   //
+        writebitst(state, 0x13,0x9E,0x09,0x0F); //  ...
+        writeregt(state, 0x13,0x9F,0xFB);   //
+
+        writeregx(state, 0x00,0x18,0x01);   // Disable ADC 4
+        writeregt(state, 0x00,0x43,0x0A);   // Disable ADC 2 // This looks 
broken (see enable)
+        writeregt(state, 0x00,0x41,0x0A);   // Disable ADC 1
+        writeregt(state, 0x00,0x30,0x00);   // Disable ADC Clock
+        writeregt(state, 0x00,0x2F,0x00);   // Disable RF level Monitor
+        writeregt(state, 0x00,0x2C,0x00);   // Disable Demod Clock
+        state->state = Sleep;
+}
+
+static void ActiveC2_to_Sleep(struct cxd_state *state)
+{
+       if (state->state <= Sleep ) 
+               return;
+       
+        writeregt(state, 0x00,0xC3,0x01);   // Disable TS
+        writeregt(state, 0x00,0x80,0x3F);   // Enable HighZ 1
+        writeregt(state, 0x00,0x81,0xFF);   // Enable HighZ 2
+
+        writeregt(state, 0x20,0xC2,0x11);   // 
+        writebitst(state, 0x25,0x6A,0x02,0x03);   // 
+        {
+               static u8 data[3] = { 0x07, 0x61, 0x36 };
+               writeregst(state, 0x25,0x89,data,sizeof(data));   // 
+       }        
+       writebitst(state, 0x25,0xCB,0x05,0x07);   // 
+        {
+               static u8 data[4] = { 0x2E, 0xE0, 0x2E, 0xE0 };
+               writeregst(state, 0x25,0xDC,data,sizeof(data));   // 
+        }        
+       writeregt(state, 0x25,0xE2,0x2F);   // 
+       writeregt(state, 0x25,0xE5,0x2F);   // 
+        writebitst(state, 0x27,0x20,0x00,0x01); //
+        writebitst(state, 0x27,0x35,0x00,0x01); //
+        writebitst(state, 0x27,0xD9,0x19,0x3F); //
+        writebitst(state, 0x2A,0x78,0x01,0x07); //
+        writeregt(state, 0x2A,0x86,0x08); //
+        writeregt(state, 0x2A,0x88,0x14); //
+        writebitst(state, 0x2B,0x2B,0x00,0x1F); //
+        {
+               u8 data[2] = { 0x75, 0x75 };
+               writeregst(state, 0x2D,0x24,data,sizeof(data));
+        }
+       
+        writeregx(state, 0x00,0x18,0x01);   // Disable ADC 4
+       writeregt(state, 0x00,0x43,0x0A);   // Disable ADC 2 // This looks 
broken (see enable)
+        writeregt(state, 0x00,0x41,0x0A);   // Disable ADC 1
+        writeregt(state, 0x00,0x30,0x00);   // Disable ADC Clock
+        writeregt(state, 0x00,0x2F,0x00);   // Disable RF level Monitor
+        writeregt(state, 0x00,0x2C,0x00);   // Disable Demod Clock
+        state->state = Sleep;
+}
+
+static int ConfigureTS(struct cxd_state *state, enum EDemodState newDemodState)
+{
+       int status = 0;
+
+       ///* OSERCKMODE  OSERDUTYMODE  OTSCKPERIOD  OREG_CKSEL_TSIF             
               */
+       // {      1,          1,            8,             0        }, /* High 
Freq, full rate */
+       // {      1,          1,            8,             1        }, /* Mid 
Freq,  full rate */
+       // {      1,          1,            8,             2        }, /* Low 
Freq,  full rate */
+       // {      2,          2,            16,            0        }, /* High 
Freq, half rate */
+       // {      2,          2,            16,            1        }, /* Mid 
Freq,  half rate */
+       // {      2,          2,            16,            2        }  /* Low 
Freq,  half rate */
+
+        u8 OSERCKMODE = 1;
+        u8 OSERDUTYMODE = 1;
+        u8 OTSCKPERIOD = 8;
+        u8 OREG_CKSEL_TSIF = state->SerialClockFrequency;
+       
+        if (state->SerialClockFrequency >= 3 ) {
+               OSERCKMODE = 2;
+               OSERDUTYMODE = 2;
+               OTSCKPERIOD = 16;
+               OREG_CKSEL_TSIF = state->SerialClockFrequency - 3;
+        }
+        writebitst(state, 0x00, 0xC4, OSERCKMODE, 0x03); // OSERCKMODE
+       writebitst(state, 0x00, 0xD1, OSERDUTYMODE, 0x03); // OSERDUTYMODE
+       writeregt(state, 0x00, 0xD9, OTSCKPERIOD); // OTSCKPERIOD
+        writebitst(state, 0x00, 0x32, 0x00, 0x01); // Disable TS IF
+        writebitst(state, 0x00, 0x33, OREG_CKSEL_TSIF, 0x03); // 
OREG_CKSEL_TSIF
+        writebitst(state, 0x00, 0x32, 0x01, 0x01); // Enable TS IF
+       
+        if (newDemodState == ActiveT) 
+               writebitst(state, 0x10, 0x66, 0x01, 0x01);
+        if (newDemodState == ActiveC)
+               writebitst(state, 0x40, 0x66, 0x01, 0x01);
+       
+       return status;
+}
+
+static void BandSettingT(struct cxd_state *state, u32 iffreq)
+{
+       u8 IF_data[3] = { (iffreq >> 16) & 0xff, (iffreq >> 8) & 0xff, iffreq & 
0xff};
+       
+        switch (state->bw) {
+       case 8:
+       {
+               static u8 TR_data[] = { 0x11, 0xF0, 0x00, 0x00, 0x00 };
+               static u8 CL_data[] = { 0x01, 0xE0 };
+               static u8 NF_data[] = { 0x01, 0x02 };
+               
+               writeregst(state, 0x10,0x9F,TR_data,sizeof(TR_data));   // 
Timing recovery
+               // Add EQ Optimisation for tuner here
+               writeregst(state, 0x10,0xB6,IF_data,sizeof(IF_data));   // 
iffreq
+               writebitst(state, 0x10,0xD7,0x00,0x07);   // System Bandwidth
+               writeregst(state, 0x10,0xD9,CL_data,sizeof(CL_data));   // core 
latency 
+               writeregst(state, 0x17,0x38,NF_data,sizeof(NF_data));   // 
notch filter 
+               break;
+       }
+       case 7:
+       {
+               static u8 TR_data[] = { 0x14, 0x80, 0x00, 0x00, 0x00 };
+               static u8 CL_data[] = { 0x12, 0xF8 };
+               static u8 NF_data[] = { 0x00, 0x03 };
+               
+               writeregst(state, 0x10,0x9F,TR_data,sizeof(TR_data));   // 
Timing recovery
+               // Add EQ Optimisation for tuner here
+               writeregst(state, 0x10,0xB6,IF_data,sizeof(IF_data));   // 
iffreq
+               writebitst(state, 0x10,0xD7,0x02,0x07);   // System Bandwidth
+               writeregst(state, 0x10,0xD9,CL_data,sizeof(CL_data));   // core 
latency 
+               writeregst(state, 0x17,0x38,NF_data,sizeof(NF_data));   // 
notch filter 
+               break;
+       }
+       case 6:
+       {
+               static u8 TR_data[] = { 0x17, 0xEA, 0xAA, 0xAA, 0xAA };
+               static u8 CL_data[] = { 0x1F, 0xDC };
+               static u8 NF_data[] = { 0x00, 0x03 };
+
+               writeregst(state, 0x10,0x9F,TR_data,sizeof(TR_data));   // 
Timing recovery
+               // Add EQ Optimisation for tuner here
+               
+               writeregst(state, 0x10,0xB6,IF_data,sizeof(IF_data));   // 
iffreq
+               writebitst(state, 0x10,0xD7,0x04,0x07);   // System Bandwidth
+               writeregst(state, 0x10,0xD9,CL_data,sizeof(CL_data));   // core 
latency 
+               writeregst(state, 0x17,0x38,NF_data,sizeof(NF_data));   // 
notch filter 
+               break;
+       }
+       case 5:
+       {
+               static u8 TR_data[] = { 0x1C, 0xB3, 0x33, 0x33, 0x33 };
+               static u8 CL_data[] = { 0x26, 0x3C };
+               static u8 NF_data[] = { 0x00, 0x03 };
+                   
+               writeregst(state, 0x10,0x9F,TR_data,sizeof(TR_data));   // 
Timing recovery
+               // Add EQ Optimisation for tuner here
+               
+               writeregst(state, 0x10,0xB6,IF_data,sizeof(IF_data));   // 
iffreq
+               
+               writebitst(state, 0x10,0xD7,0x06,0x07);   // System Bandwidth
+               writeregst(state, 0x10,0xD9,CL_data,sizeof(CL_data));   // core 
latency 
+               writeregst(state, 0x17,0x38,NF_data,sizeof(NF_data));   // 
notch filter 
+                break;
+       }
+       }
+}
+
+static void Sleep_to_ActiveT(struct cxd_state *state, u32 iffreq)
+{
+       printk("%s\n", __FUNCTION__);
+
+        ConfigureTS(state, ActiveT);
+       
+        writeregx(state, 0x00,0x17,0x01);   // Mode
+        writeregt(state, 0x00,0x2C,0x01);   // Demod Clock
+        writeregt(state, 0x00,0x2F,0x00);   // Disable RF Monitor
+        writeregt(state, 0x00,0x30,0x00);   // Enable ADC Clock
+        writeregt(state, 0x00,0x41,0x1A);   // Enable ADC1
+       
+       {
+            u8 data[2] = { 0x09, 0x54 };  // 20.5 MHz
+            //u8 data[2] = { 0x0A, 0xD4 };  // 41 MHz
+            writeregst(state, 0x00,0x43,data,2);   // Enable ADC 2+3
+        }
+       writeregx(state, 0x00,0x18,0x00);   // Enable ADC 4
+       
+        // -- till here identical to DVB-C (apart from mode)
+       
+        writebitst(state, 0x10,0xD2,0x0C,0x1F); // IF AGC Gain
+        writeregt(state, 0x11,0x6A,0x48); // BB AGC Target Level
+
+        writebitst(state, 0x10,0xA5,0x00,0x01); // ASCOT Off
+
+        writebitst(state, 0x18,0x36,0x40,0x07); // Pre RS Monitoring
+        writebitst(state, 0x18,0x30,0x01,0x01); // FEC Autorecover
+        writebitst(state, 0x18,0x31,0x01,0x01); // FEC Autorecover
+
+        writebitst(state, 0x00,0xCE,0x01,0x01); // TSIF ONOPARITY
+        writebitst(state, 0x00,0xCF,0x01,0x01); // TSIF ONOPARITY_MANUAL_ON
+
+        BandSettingT(state, iffreq);
+
+        writeregt(state, 0x00,0x80,0x28); // Disable HiZ Setting 1
+       writeregt(state, 0x00,0x81,0x00); // Disable HiZ Setting 2
+}
+
+static void BandSettingT2(struct cxd_state *state, u32 iffreq)
+{
+       u8 IF_data[3] = { (iffreq >> 16) & 0xff, (iffreq >> 8) & 0xff, iffreq & 
0xff};
+
+        switch (state->bw) {
+       default:
+       case 8:
+       {
+               static u8 TR_data[] = { 0x11, 0xF0, 0x00, 0x00, 0x00 };
+               writeregst(state, 0x20,0x9F,TR_data,sizeof(TR_data));   // 
Timing recovery
+               // Add EQ Optimisation for tuner here
+               writeregst(state, 0x10,0xB6,IF_data,sizeof(IF_data));   // 
iffreq
+               writebitst(state, 0x10,0xD7,0x00,0x07);   // System Bandwidth
+       }
+       break;
+       case 7:
+       {
+               static u8 TR_data[] = { 0x14, 0x80, 0x00, 0x00, 0x00 };
+               writeregst(state, 0x20,0x9F,TR_data,sizeof(TR_data));   // 
Timing recovery
+               // Add EQ Optimisation for tuner here
+               writeregst(state, 0x10,0xB6,IF_data,sizeof(IF_data));   // 
iffreq
+               writebitst(state, 0x10,0xD7,0x02,0x07);   // System Bandwidth
+       }
+       break;
+       case 6:
+       {
+               static u8 TR_data[] = { 0x17, 0xEA, 0xAA, 0xAA, 0xAA };
+               writeregst(state, 0x20,0x9F,TR_data,sizeof(TR_data));   // 
Timing recovery
+               // Add EQ Optimisation for tuner here
+               writeregst(state, 0x10,0xB6,IF_data,sizeof(IF_data));   // 
iffreq
+               writebitst(state, 0x10,0xD7,0x04,0x07);   // System Bandwidth
+       }
+       break;
+       case 5:
+       {
+               static u8 TR_data[] = { 0x1C, 0xB3, 0x33, 0x33, 0x33 };
+               writeregst(state, 0x20,0x9F,TR_data,sizeof(TR_data));   // 
Timing recovery
+               // Add EQ Optimisation for tuner here
+               writeregst(state, 0x10,0xB6,IF_data,sizeof(IF_data));   // 
iffreq
+               writebitst(state, 0x10,0xD7,0x06,0x07);   // System Bandwidth
+       }
+       break;
+       case 1: // 1.7 MHz
+       {
+               static u8 TR_data[] = { 0x58, 0xE2, 0xAF, 0xE0, 0xBC };
+               writeregst(state, 0x20,0x9F,TR_data,sizeof(TR_data));   // 
Timing recovery
+               // Add EQ Optimisation for tuner here
+               
+               writeregst(state, 0x10,0xB6,IF_data,sizeof(IF_data));   // 
iffreq
+
+               writebitst(state, 0x10,0xD7,0x03,0x07);   // System Bandwidth
+       }
+       break;
+        }
+}
+
+
+static void Sleep_to_ActiveT2(struct cxd_state *state, u32 iffreq)
+{
+        ConfigureTS(state, ActiveT2);
+       
+        writeregx(state, 0x00, 0x17, 0x02);   // Mode
+        writeregt(state, 0x00, 0x2C, 0x01);   // Demod Clock
+        writeregt(state, 0x00, 0x2F, 0x00);   // Disable RF Monitor
+        writeregt(state, 0x00, 0x30, 0x00);   // Enable ADC Clock
+        writeregt(state, 0x00, 0x41, 0x1A);   // Enable ADC1
+
+        {
+            u8 data[2] = { 0x09, 0x54 };  // 20.5 MHz
+            //u8 data[2] = { 0x0A, 0xD4 };  // 41 MHz
+            writeregst(state, 0x00, 0x43,data,2);   // Enable ADC 2+3
+        }
+        writeregx(state, 0x00, 0x18, 0x00);   // Enable ADC 4
+
+        writebitst(state, 0x10, 0xD2, 0x0C, 0x1F); //IFAGC  coarse gain
+        writeregt(state, 0x11, 0x6A, 0x50); // BB AGC Target Level
+        writebitst(state, 0x10, 0xA5, 0x00, 0x01); // ASCOT Off
+
+        writeregt(state, 0x20, 0x8B, 0x3C); // SNR Good count
+        writebitst(state, 0x2B, 0x76, 0x20, 0x70); // Noise Gain ACQ
+
+        writebitst(state, 0x00, 0xCE, 0x01, 0x01); // TSIF ONOPARITY
+        writebitst(state, 0x00, 0xCF, 0x01, 0x01); // TSIF ONOPARITY_MANUAL_ON
+
+        writeregt(state, 0x13, 0x83, 0x10); // T2 Inital settings
+        writeregt(state, 0x13, 0x86, 0x34); //  ...
+        writebitst(state, 0x13, 0x9E, 0x09, 0x0F); //  ...
+        writeregt(state, 0x13, 0x9F, 0xD8); //  ...
+
+        BandSettingT2(state, iffreq);
+
+        writeregt(state, 0x00, 0x80, 0x28); // Disable HiZ Setting 1
+        writeregt(state, 0x00, 0x81, 0x00); // Disable HiZ Setting 2
+}
+
+
+static void BandSettingC(struct cxd_state *state, u32 iffreq)
+{
+        u8 data[3];
+        data[0] = (iffreq >> 16) & 0xFF;
+        data[1] = (iffreq >>  8) & 0xFF;
+        data[2] = (iffreq      ) & 0xFF;
+        writeregst(state, 0x10, 0xB6, data, 3);   // iffreq
+}
+
+static void Sleep_to_ActiveC(struct cxd_state *state, u32 iffreq)
+{
+        ConfigureTS(state, ActiveC);
+       
+        writeregx(state, 0x00, 0x17, 0x04);   // Mode
+        writeregt(state, 0x00, 0x2C, 0x01);   // Demod Clock
+        writeregt(state, 0x00, 0x2F, 0x00);   // Disable RF Monitor
+        writeregt(state, 0x00, 0x30, 0x00);   // Enable ADC Clock
+        writeregt(state, 0x00, 0x41, 0x1A);   // Enable ADC1
+
+        {
+               u8 data[2] = { 0x09, 0x54 };  // 20.5 MHz
+               //u8 data[2] = { 0x0A, 0xD4 };  // 41 MHz
+               writeregst(state, 0x00, 0x43,data,2);   // Enable ADC 2+3
+        }
+        writeregx(state, 0x00, 0x18, 0x00);   // Enable ADC 4
+
+        writebitst(state, 0x10, 0xD2, 0x09, 0x1F); // IF AGC Gain
+        writeregt(state, 0x11, 0x6A, 0x48); // BB AGC Target Level
+        writebitst(state, 0x10, 0xA5, 0x00, 0x01); // ASCOT Off
+
+        writebitst(state, 0x40, 0xC3, 0x00, 0x04); // OREG_BNDET_EN_64
+
+        writebitst(state, 0x00, 0xCE, 0x01, 0x01); // TSIF ONOPARITY
+        writebitst(state, 0x00, 0xCF, 0x01, 0x01); // TSIF ONOPARITY_MANUAL_ON
+
+        BandSettingC(state, iffreq);
+
+        writeregt(state, 0x00, 0x80, 0x28); // Disable HiZ Setting 1
+        writeregt(state, 0x00, 0x81, 0x00); // Disable HiZ Setting 2
+}
+
+static void BandSettingC2(struct cxd_state *state, u32 iffreq)
+{
+       u8 IF_data[3] = { (iffreq >> 16) & 0xff, (iffreq >> 8) & 0xff, iffreq & 
0xff};
+
+        switch (state->bw) {
+       case 8:
+       {
+               static u8 TR_data[] = { 0x11, 0xF0, 0x00, 0x00, 0x00 };
+               static u8 data[2] = { 0x11, 0x9E };
+
+               writeregst(state, 0x20,0x9F,TR_data,sizeof(TR_data));   // 
Timing recovery
+               // Add EQ Optimisation for tuner here
+               
+               writeregst(state, 0x10,0xB6,IF_data,sizeof(IF_data));   // 
iffreq
+
+               writebitst(state, 0x10,0xD7,0x00,0x07);   // System Bandwidth
+               
+               writeregst(state, 0x50,0xEC,data,sizeof(data));   // timeout
+               writeregt(state, 0x50,0xEF,0x11);
+               writeregt(state, 0x50,0xF1,0x9E);
+       }
+       break;
+       case 6:
+       {
+               static u8 TR_data[] = { 0x17, 0xEA, 0xAA, 0xAA, 0xAA };
+               static u8 data[2] = { 0x17, 0x70 };
+
+               writeregst(state, 0x20,0x9F,TR_data,sizeof(TR_data));   // 
Timing recovery
+               // Add EQ Optimisation for tuner here
+               writeregst(state, 0x10,0xB6,IF_data,sizeof(IF_data));   // 
iffreq
+               writebitst(state, 0x10,0xD7,0x04,0x07);   // System Bandwidth
+               
+               writeregst(state, 0x50,0xEC,data,sizeof(data));   // timeout
+               writeregt(state, 0x50,0xEF,0x17);
+               writeregt(state, 0x50,0xF1,0x70);
+       }
+       break;
+        }
+}
+
+static void Sleep_to_ActiveC2(struct cxd_state *state, u32 iffreq)
+{
+        ConfigureTS(state, ActiveC2);
+
+        writeregx(state, 0x00,0x17,0x05);   // Mode
+        writeregt(state, 0x00,0x2C,0x01);   // Demod Clock
+        writeregt(state, 0x00,0x2F,0x00);   // Disable RF Monitor
+        writeregt(state, 0x00,0x30,0x00);   // Enable ADC Clock
+        writeregt(state, 0x00,0x41,0x1A);   // Enable ADC1
+       
+        {
+               u8 data[2] = { 0x09, 0x54 };  // 20.5 MHz
+               //u8 data[2] = { 0x0A, 0xD4 };  // 41 MHz
+               writeregst(state, 0x00,0x43,data,sizeof(data));   // Enable ADC 
2+3
+        }
+        writeregx(state, 0x00,0x18,0x00);   // Enable ADC 4
+
+       writebitst(state, 0x10,0xD2,0x0C,0x1F); //IFAGC  coarse gain
+       writeregt(state, 0x11,0x6A,0x50); // BB AGC Target Level
+        writebitst(state, 0x10,0xA5,0x00,0x01); // ASCOT Off
+
+        writebitst(state, 0x00,0xCE,0x01,0x01); // TSIF ONOPARITY
+        writebitst(state, 0x00,0xCF,0x01,0x01); // TSIF ONOPARITY_MANUAL_ON
+       
+        writeregt(state, 0x20,0xC2,0x00); //
+       writebitst(state, 0x25,0x6A,0x00,0x03); //
+       {
+               u8 data[3] = { 0x0C, 0xD1, 0x40 };
+               writeregst(state, 0x25,0x89,data,sizeof(data));
+        }
+        writebitst(state, 0x25,0xCB,0x01,0x07); //
+        {
+               u8 data[4] = { 0x7B, 0x00, 0x7B, 0x00 };
+               writeregst(state, 0x25,0xDC,data,sizeof(data));
+        }
+        writeregt(state, 0x25,0xE2,0x30); //
+        writeregt(state, 0x25,0xE5,0x30); //
+        writebitst(state, 0x27,0x20,0x01,0x01); //
+        writebitst(state, 0x27,0x35,0x01,0x01); //
+        writebitst(state, 0x27,0xD9,0x18,0x3F); //
+        writebitst(state, 0x2A,0x78,0x00,0x07); //
+        writeregt(state, 0x2A,0x86,0x20); //
+        writeregt(state, 0x2A,0x88,0x32); //
+        writebitst(state, 0x2B,0x2B,0x10,0x1F); //
+        {
+               u8 data[2] = { 0x01, 0x01 };
+               writeregst(state, 0x2D,0x24,data,sizeof(data));
+        }
+
+        BandSettingC2(state, iffreq);
+       
+        writeregt(state, 0x00,0x80,0x28); // Disable HiZ Setting 1
+        writeregt(state, 0x00,0x81,0x00); // Disable HiZ Setting 2
+}
+
+
+static void BandSettingIT(struct cxd_state *state, u32 iffreq)
+{
+       u8 IF_data[3] = { (iffreq >> 16) & 0xff, (iffreq >> 8) & 0xff, iffreq & 
0xff};
+
+        switch (state->bw) {
+       default:
+       case 8:
+       {
+               static u8 TR_data[] = { 0x0F, 0x22, 0x80, 0x00, 0x00 };   // 
20.5/41
+               static u8 CL_data[] = { 0x15, 0xA8 };
+
+               // static u8 TR_data[] = { 0x11, 0xB8, 0x00, 0x00, 0x00 };  // 
24
+               writeregst(state, 0x10,0x9F,TR_data,sizeof(TR_data));   // 
Timing recovery
+               // Add EQ Optimisation for tuner here
+               writeregst(state, 0x10,0xB6,IF_data,sizeof(IF_data));   // 
iffreq
+               
+               writeregt(state, 0x10,0xD7,0x00);   // System Bandwidth
+               //static u8 CL_data[] = { 0x13, 0xFC };
+               writeregst(state, 0x10,0xD9,CL_data,sizeof(CL_data));   // core 
latency 
+       }
+       break;
+       case 7:
+       {
+               static u8 TR_data[] = { 0x11, 0x4c, 0x00, 0x00, 0x00 };
+               static u8 CL_data[] = { 0x1B, 0x5D };
+
+               //static u8 TR_data[] = { 0x14, 0x40, 0x00, 0x00, 0x00 };
+               writeregst(state, 0x10,0x9F,TR_data,sizeof(TR_data));   // 
Timing recovery
+               // Add EQ Optimisation for tuner here
+               writeregst(state, 0x10,0xB6,IF_data,sizeof(IF_data));   // 
iffreq
+               
+               writeregt(state, 0x10,0xD7,0x02);   // System Bandwidth
+               //static u8 CL_data[] = { 0x1A, 0xFA };
+               writeregst(state, 0x10,0xD9,CL_data,sizeof(CL_data));   // core 
latency 
+       }
+       break;
+       case 6:
+       {
+               static u8 TR_data[] = { 0x14, 0x2E, 0x00, 0x00, 0x00 };
+               static u8 CL_data[] = { 0x1F, 0xEC };
+               //static u8 TR_data[] = { 0x17, 0xA0, 0x00, 0x00, 0x00 };
+               //static u8 CL_data[] = { 0x1F, 0x79 };
+               
+               writeregst(state, 0x10,0x9F,TR_data,sizeof(TR_data));   // 
Timing recovery
+               // Add EQ Optimisation for tuner here
+               writeregst(state, 0x10,0xB6,IF_data,sizeof(IF_data));   // 
iffreq
+               
+               writeregt(state, 0x10,0xD7,0x04);   // System Bandwidth
+               writeregst(state, 0x10, 0xD9, CL_data, sizeof(CL_data));   // 
core latency 
+       }
+       break;
+        }
+}
+
+static void Sleep_to_ActiveIT(struct cxd_state *state, u32 iffreq)
+{
+       static u8 data2[3] = { 0xB9,0xBA,0x63 };  // 20.5/41 MHz
+        //static u8 data2[3] = { 0xB7,0x1B,0x00 };  // 24 MHz
+        static u8 TSIF_data[2] = { 0x61,0x60 } ; // 20.5/41 MHz
+        //static u8 TSIF_data[2] = { 0x60,0x00 } ; // 24 MHz
+
+       printk("%s\n", __FUNCTION__);
+
+        ConfigureTS(state, ActiveIT);
+       
+        // writeregx(state, 0x00,0x17,0x01);   // 2838 has only one Mode
+        writeregt(state, 0x00,0x2C,0x01);   // Demod Clock
+       writeregt(state, 0x00,0x2F,0x00);   // Disable RF Monitor
+        writeregt(state, 0x00,0x30,0x00);   // Enable ADC Clock
+        writeregt(state, 0x00,0x41,0x1A);   // Enable ADC1
+       
+        {
+               u8 data[2] = { 0x09, 0x54 };  // 20.5 MHz, 24 MHz
+               //u8 data[2] = { 0x0A, 0xD4 };  // 41 MHz
+               writeregst(state, 0x00,0x43,data,2);   // Enable ADC 2+3
+        }
+        writeregx(state, 0x00,0x18,0x00);   // Enable ADC 4
+
+        writeregst(state, 0x60,0xA8,data2,sizeof(data2));
+
+        writeregst(state, 0x10,0xBF,TSIF_data,sizeof(TSIF_data));
+
+        writeregt(state, 0x10,0xE2,0xCE); // OREG_PNC_DISABLE
+        writebitst(state, 0x10,0xA5,0x00,0x01); // ASCOT Off
+        
+        BandSettingIT(state, iffreq);
+
+        writeregt(state, 0x00,0x80,0x28); // Disable HiZ Setting 1
+        writeregt(state, 0x00,0x81,0x00); // Disable HiZ Setting 2
+}
+
+static void T2_SetParameters(struct cxd_state *state)
+{
+        u8 Profile = 0x01;    // Profile Base
+        u8 notT2time = 12;    // early unlock detection time
+       
+        //u8 Profile = 0x05;       // Lite
+        //u8 notT2time = 40;
+       
+        //u8 Profile = 0x00;       // Any
+        //u8 notT2time = 40;
+       
+       
+        if (state->PLPNumber != 0xffffffff) {
+               writeregt(state, 0x23, 0xAF, state->PLPNumber);
+               writeregt(state, 0x23, 0xAD, 0x01);
+       } else {
+               writeregt(state, 0x23, 0xAD, 0x00);
+        }
+       
+        writebitst(state, 0x2E, 0x10, Profile, 0x07);
+       writeregt(state, 0x2B, 0x19, notT2time);
+}
+
+static void C2_ReleasePreset(struct cxd_state *state)
+{
+        {
+               static u8 data[2] = { 0x02, 0x80};
+               writeregst(state, 0x27,0xF4,data,sizeof(data));
+       }
+        writebitst(state, 0x27,0x51,0x40,0xF0);
+        writebitst(state, 0x27,0x73,0x07,0x0F);
+        writebitst(state, 0x27,0x74,0x19,0x3F);
+        writebitst(state, 0x27,0x75,0x19,0x3F);
+        writebitst(state, 0x27,0x76,0x19,0x3F);
+        if (state->bw == 6 ) {
+               static u8 data[5] = { 0x17, 0xEA, 0xAA, 0xAA, 0xAA};
+               writeregst(state, 0x20,0x9F,data,sizeof(data));
+        } else {
+               static u8 data[5] = { 0x11, 0xF0, 0x00, 0x00, 0x00};
+               writeregst(state, 0x20,0x9F,data,sizeof(data));
+        }
+        writebitst(state, 0x27,0xC9,0x07,0x07);
+       writebitst(state, 0x20,0xC2,0x11,0x33);
+        {
+               static u8 data[10] = { 0x16, 0xF0, 0x2B, 0xD8, 0x16, 0x16, 
0xF0, 0x2C, 0xD8, 0x16 };
+               writeregst(state, 0x2A,0x20,data,sizeof(data));
+        }
+        {
+               static u8 data[4] = { 0x00, 0x00, 0x00, 0x00 };
+               writeregst(state, 0x50,0x6B,data,sizeof(data));
+        }
+        writebitst(state, 0x50,0x6F,0x00,0x40); // Disable Preset
+}
+
+static void C2_DemodSetting2(struct cxd_state *state)
+{
+       u8 data[6];
+        u32 TunePosition = state->frontend.dtv_property_cache.frequency / 1000;
+       
+        if (state->bw == 6) {
+               TunePosition = ((TunePosition * 1792) / 3) / 1000;
+        } else {
+               TunePosition = (TunePosition * 448) / 1000;
+        }
+        TunePosition = ((TunePosition + 6) / 12) * 12;
+
+       printk("TunePosition = %u\n", TunePosition);
+
+        data[0] = ( (TunePosition >> 16) & 0xFF );
+        data[1] = ( (TunePosition >>  8) & 0xFF );
+        data[2] = ( (TunePosition      ) & 0xFF );
+        data[3] = 0x02;
+        data[4] = (state->DataSliceID & 0xFF); 
+        data[5] = (state->PLPNumber & 0xFF);   
+        writeregst(state, 0x50, 0x7A, data, sizeof(data));
+        writebitst(state, 0x50, 0x87, 0x01, 0x01); /* Preset Clear */
+}
+
+static void Stop(struct cxd_state *state)
+{
+       writeregt(state, 0x00,0xC3,0x01); /* Disable TS */
+}
+
+static void ShutDown(struct cxd_state *state)
+{
+       switch (state->state) {
+        case ActiveT2: 
+               ActiveT2_to_Sleep(state);
+               break;
+        case ActiveC2: 
+               ActiveC2_to_Sleep(state);
+               break;
+        default:
+               Active_to_Sleep(state);
+               break;
+       }
+}
+
+static int gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct cxd_state *state = fe->demodulator_priv;
+       
+       return writebitsx(state, 0xFF, 0x08, enable ? 0x01 : 0x00, 0x01);
+}
+
+static void release(struct dvb_frontend* fe)
+{
+       struct cxd_state *state = fe->demodulator_priv;
+
+       Stop(state);
+       ShutDown(state);
+       kfree(state);
+}
+
+static int Start(struct cxd_state *state, u32 IntermediateFrequency)
+{
+       enum EDemodState newDemodState = Unknown;
+       u32 iffreq;
+       
+       if (state->state < Sleep ) {
+               return -EINVAL;
+       }
+       
+       iffreq = MulDiv32(IntermediateFrequency, 16777216, 41000000);
+
+       switch(state->omode) {
+        case OM_DVBT: 
+               if (state->type == CXD2838 ) 
+                       return -EINVAL;
+               newDemodState = ActiveT; 
+               break;
+        case OM_DVBT2: 
+               if (state->type == CXD2838 ) 
+                       return -EINVAL;
+               newDemodState = ActiveT2; 
+               break;
+        case OM_DVBC:
+        case OM_QAM_ITU_C:  
+               if (state->type == CXD2838 ) 
+                       return -EINVAL;
+               newDemodState = ActiveC; 
+               break;
+        case OM_DVBC2:
+               if (state->type != CXD2843 ) 
+                       return -EINVAL;
+               newDemodState = ActiveC2; 
+               break;
+        case OM_ISDBT: 
+               if (state->type != CXD2838 ) 
+                       return -EINVAL;
+               newDemodState = ActiveIT; 
+               break;
+        default:
+               return -EINVAL;
+       }
+       
+       state->LockTimeout = 0;
+       state->TSLockTimeout = 0;
+       state->L1PostTimeout = 0;
+       state->FirstTimeLock = 1;
+       
+       if (state->state == newDemodState ) {
+               writeregt(state, 0x00, 0xC3, 0x01);   /* Disable TS Output */
+               switch (newDemodState) {
+               case ActiveT:  
+                       writeregt(state, 0x10,0x67, 0x00);  /* Stick with HP ( 
0x01 = LP ) */
+                       BandSettingT(state, iffreq);  
+                       break;
+               case ActiveT2: 
+                       T2_SetParameters(state);
+                       BandSettingT2(state, iffreq);
+                       break;
+               case ActiveC:
+                       BandSettingC(state, iffreq);
+                       break;
+               case ActiveC2: 
+                       BandSettingC2(state, iffreq);
+                       C2_ReleasePreset(state);
+                       C2_DemodSetting2(state);
+                       break;
+               case ActiveIT:
+                       BandSettingIT(state, iffreq);
+                       break;
+               default:
+                       break;
+               }
+       } else {
+               if (state->state > Sleep ) {
+                       switch (state->state) {
+                       case ActiveT2: 
+                               ActiveT2_to_Sleep(state);
+                               break;
+                       case ActiveC2: 
+                               ActiveC2_to_Sleep(state);
+                               break;
+                       default:
+                               Active_to_Sleep(state);
+                               break;
+                       }
+               }
+               switch (newDemodState) {
+               case ActiveT:  
+                       writeregt(state, 0x10,0x67, 0x00);  // Stick with HP ( 
0x01 = LP )
+                       Sleep_to_ActiveT(state, iffreq);  
+                       break;
+               case ActiveT2: 
+                       T2_SetParameters(state);
+                       Sleep_to_ActiveT2(state, iffreq);
+                       break;
+               case ActiveC:  
+                       Sleep_to_ActiveC(state, iffreq);
+                       break;
+               case ActiveC2:
+                       Sleep_to_ActiveC2(state, iffreq);
+                       C2_ReleasePreset(state);
+                       C2_DemodSetting2(state);
+                       break;
+               case ActiveIT:
+                       Sleep_to_ActiveIT(state, iffreq);
+                       break;
+               default:
+                       break;
+               }
+       }               
+       state->state = newDemodState;
+       writeregt(state, 0x00, 0xFE, 0x01);   // SW Reset
+       writeregt(state, 0x00, 0xC3, 0x00);   // Enable TS Output
+       
+       return 0;
+}
+
+static int set_parameters(struct dvb_frontend *fe)
+{
+       int stat;
+       struct cxd_state *state = fe->demodulator_priv;
+       u32 IF;
+
+       switch (fe->dtv_property_cache.delivery_system) {
+       case SYS_DVBC_ANNEX_A:
+               state->omode = OM_DVBC;
+               break;
+       case SYS_DVBC2:
+               state->omode = OM_DVBC2;
+               break;
+       case SYS_DVBT:
+               state->omode = OM_DVBT;
+               break;
+       case SYS_DVBT2:
+               state->omode = OM_DVBT2;
+               break;
+       case SYS_ISDBT:
+               state->omode = OM_ISDBT;
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (fe->ops.tuner_ops.set_params)
+               fe->ops.tuner_ops.set_params(fe);
+       state->bandwidth = fe->dtv_property_cache.bandwidth_hz;
+       state->bw = (fe->dtv_property_cache.bandwidth_hz + 999999) / 1000000;
+       state->DataSliceID = 0;//fe->dtv_property_cache.slice_id;
+       state->PLPNumber = fe->dtv_property_cache.stream_id;
+       fe->ops.tuner_ops.get_if_frequency(fe, &IF);
+       stat = Start(state, IF);
+       return stat;
+}
+
+
+static void init(struct cxd_state *state)
+{
+        u8 data[2] = {0x00, 0x00}; // 20.5 MHz 
+
+       state->omode = OM_NONE;
+       state->state   = Unknown;
+
+       writeregx(state, 0xFF, 0x02, 0x00);
+       msleep(4);
+       writeregx(state, 0x00, 0x10, 0x01);
+        
+       writeregsx(state, 0x00, 0x13, data, 2);
+        writeregx(state, 0x00, 0x10, 0x00);
+        msleep(2);
+        state->curbankx = 0xFF;
+        state->curbankt = 0xFF;
+        
+        writeregt(state, 0x00, 0x43, 0x0A);
+        writeregt(state, 0x00, 0x41, 0x0A);
+        if (state->type == CXD2838)
+               writeregt(state, 0x60, 0x5A, 0x00);
+       
+        writebitst(state, 0x10, 0xCB, 0x00, 0x40);
+        writeregt(state, 0x10, 0xCD, state->IF_FS);
+
+        writebitst(state, 0x00, 0xC4, 0x80, 0x98);
+        writebitst(state, 0x00, 0xC5, 0x00, 0x07);
+        writebitst(state, 0x00, 0xCB, 0x00, 0x01);
+        writebitst(state, 0x00, 0xC6, 0x00, 0x1D);
+        writebitst(state, 0x00, 0xC8, 0x00, 0x1D);
+        writebitst(state, 0x00, 0xC9, 0x00, 0x1D);
+        writebitst(state, 0x00, 0x83, 0x00, 0x07);
+       writeregt(state, 0x00, 0x84, 0x00);
+        writebitst(state, 0x00, 0xD3, (state->type == CXD2838) ? 0x01 : 0x00, 
0x01);
+        writebitst(state, 0x00, 0xDE, 0x00, 0x01);
+
+        state->state = Sleep;
+}
+
+
+static void init_state(struct cxd_state *state, struct cxd2843_cfg *cfg)
+{
+       state->adrt = cfg->adr;
+       state->adrx = cfg->adr + 0x02;
+       state->curbankt = 0xff;
+       state->curbankx = 0xff;
+
+       mutex_init(&state->mutex);
+
+       state->SerialMode = 1;
+       state->ContinuousClock = 1;
+       state->SerialClockFrequency = 
+               (cfg->ts_clock >= 1 && cfg->ts_clock <= 5) ? cfg->ts_clock :  
1; // 1 = fastest (82 MBit/s), 5 = slowest
+       state->SerialClockFrequency = 1;
+       state->IF_FS = 0x50; // IF Fullscale 0x50 = 1.4V, 0x39 = 1V, 0x28 = 
0.7V 
+}
+
+static int get_tune_settings(struct dvb_frontend *fe,
+                            struct dvb_frontend_tune_settings *sets)
+{
+       switch (fe->dtv_property_cache.delivery_system) {
+       case SYS_DVBC_ANNEX_A:
+       case SYS_DVBC_ANNEX_C:
+               //return c_get_tune_settings(fe, sets);
+       default:
+               /* DVB-T: Use info.frequency_stepsize. */
+               return -EINVAL;
+       }
+}
+
+static int read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct cxd_state *state = fe->demodulator_priv;
+       u8 rdata;
+       
+       *status=0;
+       switch (state->state) {
+        case ActiveC:
+               readregst(state, 0x40, 0x88, &rdata, 1);
+               if (rdata & 0x02) 
+                       break;
+               if (rdata & 0x01) {
+                       *status |= 0x07;
+                       readregst(state, 0x40, 0x10, &rdata, 1);
+                       if (rdata & 0x20)
+                               *status |= 0x1f;
+               }
+               break;
+       case ActiveT:
+               readregst(state, 0x10, 0x10, &rdata, 1) ;
+               if (rdata & 0x10) 
+                       break;
+               if ((rdata & 0x07) == 0x06) {
+                       *status |= 0x07;
+                       if (rdata & 0x20)
+                               *status |= 0x1f;
+               }
+               break;
+       case ActiveT2:
+               readregst(state, 0x20, 0x10, &rdata, 1);
+               if (rdata & 0x10) 
+                       break;
+               if ((rdata & 0x07) == 0x06) {
+                       *status |= 0x07;
+                       if (rdata & 0x20)
+                               *status |= 0x08;
+               }
+               if (*status & 0x08) {
+                       readregst(state, 0x22, 0x12, &rdata, 1);
+                       if (rdata & 0x01)
+                               *status |= 0x10;
+               }
+               break;
+       case ActiveC2:
+               readregst(state, 0x20, 0x10, &rdata, 1);
+               if (rdata & 0x10) 
+                       break;
+               if ((rdata & 0x07) == 0x06) {
+                       *status |= 0x07;
+                       if (rdata & 0x20)
+                               *status |= 0x18;
+               }
+               if ((*status & 0x10) && state->FirstTimeLock) {
+                       u8 data;
+                       
+                       // Change1stTrial
+                       readregst(state, 0x28, 0xE6, &rdata, 1);
+                       data = rdata & 1;
+                       readregst(state, 0x50, 0x15, &rdata, 1);
+                       data |= ((rdata & 0x18) >> 2);
+                       //writebitst(state, 0x50,0x6F,rdata,0x07);
+                       state->FirstTimeLock = 0;
+               }
+               break;
+       case ActiveIT:
+               readregst(state, 0x60, 0x10, &rdata, 1);
+               if (rdata & 0x10) 
+                       break;
+               if (rdata & 0x02) {
+                       *status |= 0x07;
+                       if (rdata & 0x01)
+                               *status |= 0x18;
+               }
+               break;
+               default:
+               break;
+       }
+       state->last_status = *status;
+       return 0;
+}
+
+static int read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       //struct cxd_state *state = fe->demodulator_priv;
+
+       *ber = 0;
+       return 0;
+}
+
+static int read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       if (fe->ops.tuner_ops.get_rf_strength)
+               fe->ops.tuner_ops.get_rf_strength(fe, strength);
+       else
+               *strength = 0;
+       return 0;
+}
+
+static s32 Log10x100(u32 x)
+{
+       static u32 LookupTable[100] = {
+               101157945, 103514217, 105925373, 108392691, 110917482,
+               113501082, 116144861, 118850223, 121618600, 124451461, // 800.5 
- 809.5
+               127350308, 130316678, 133352143, 136458314, 139636836,
+               142889396, 146217717, 149623566, 153108746, 156675107, // 810.5 
- 819.5
+               160324539, 164058977, 167880402, 171790839, 175792361,
+               179887092, 184077200, 188364909, 192752491, 197242274, // 820.5 
- 829.5
+               201836636, 206538016, 211348904, 216271852, 221309471,
+               226464431, 231739465, 237137371, 242661010, 248313311, // 830.5 
- 839.5
+               254097271, 260015956, 266072506, 272270131, 278612117,
+               285101827, 291742701, 298538262, 305492111, 312607937, // 840.5 
- 849.5
+               319889511, 327340695, 334965439, 342767787, 350751874,
+               358921935, 367282300, 375837404, 384591782, 393550075, // 850.5 
- 859.5
+               402717034, 412097519, 421696503, 431519077, 441570447,
+               451855944, 462381021, 473151259, 484172368, 495450191, // 860.5 
- 869.5
+               506990708, 518800039, 530884444, 543250331, 555904257,
+               568852931, 582103218, 595662144, 609536897, 623734835, // 870.5 
- 879.5
+               638263486, 653130553, 668343918, 683911647, 699841996,
+               716143410, 732824533, 749894209, 767361489, 785235635, // 880.5 
- 889.5
+               803526122, 822242650, 841395142, 860993752, 881048873,
+               901571138, 922571427, 944060876, 966050879, 988553095, // 890.5 
- 899.5
+       };
+       s32 y;
+       int i;
+
+       if (x == 0)
+               return 0;
+       y = 800;
+       if (x >= 1000000000) {
+               x /= 10;
+               y += 100;
+       }
+
+       while (x < 100000000) {
+               x *= 10;
+               y -= 100;
+       }
+       i = 0;
+       while (i < 100 && x > LookupTable[i])
+               i += 1;
+       y += i;
+       return y;
+}
+
+#if 0
+static void GetPLPIds(struct cxd_state *state, u32 nValues, u8 *Values, u32 
*Returned)
+{
+       u8 nPids = 0;
+       
+       *Returned = 0;
+       if (state->state != ActiveT2 )
+               return;
+       if (state->last_status != 0x1f)
+               return;
+       
+       FreezeRegsT(state);
+       readregst_unlocked(state, 0x22, 0x7F, &nPids, 1);
+       
+       Values[0] = nPids;
+       if( nPids >= nValues )
+               nPids = nValues - 1;
+       
+       readregst_unlocked(state, 0x22, 0x80, &Values[1], nPids > 128 ? 128 : 
nPids);
+       
+       if( nPids > 128 )
+               readregst_unlocked(state, 0x23, 0x10, &Values[129], nPids - 
128);
+       
+        *Returned = nPids + 1;
+       
+       UnFreezeRegsT(state);
+}
+#endif
+
+static void GetSignalToNoiseIT(struct cxd_state *state, u32 *SignalToNoise)
+{
+       u8 Data[2];
+       u32 reg;
+        
+       FreezeRegsT(state);
+       readregst_unlocked(state, 0x60, 0x28, Data, sizeof(Data));
+       UnFreezeRegsT(state);
+
+        reg = (Data[0] << 8) | Data[1];
+        if (reg > 51441)
+               reg = 51441;
+
+        if (state->bw == 8) {
+               if (reg > 1143)
+                       reg = 1143;
+               *SignalToNoise = (Log10x100(reg) - Log10x100(1200 - reg)) + 220;
+        } else 
+               *SignalToNoise = Log10x100(reg) - 90;
+}
+
+static void GetSignalToNoiseC2(struct cxd_state *state, u32 *SignalToNoise)
+{
+       u8 Data[2];
+       u32 reg;
+        
+       FreezeRegsT(state);
+       readregst_unlocked(state, 0x20, 0x28, Data, sizeof(Data));
+       UnFreezeRegsT(state);
+
+        reg = (Data[0] << 8) | Data[1];
+        if (reg > 51441)
+               reg = 51441;
+
+        *SignalToNoise = (Log10x100(reg) - Log10x100(55000 - reg)) + 384;
+}
+
+
+static void GetSignalToNoiseT2(struct cxd_state *state, u32 *SignalToNoise)
+{
+       u8 Data[2];
+       u32 reg;
+        
+       FreezeRegsT(state);
+       readregst_unlocked(state, 0x20, 0x28, Data, sizeof(Data));
+       UnFreezeRegsT(state);
+       
+        reg = (Data[0] << 8) | Data[1];
+        if (reg > 10876)
+               reg = 10876;
+       
+        *SignalToNoise = (Log10x100(reg) - Log10x100(12600 - reg)) + 320;
+}
+
+static void GetSignalToNoiseT(struct cxd_state *state, u32 *SignalToNoise)
+{
+       u8 Data[2];
+       u32 reg;
+
+       FreezeRegsT(state);
+       readregst_unlocked(state, 0x10, 0x28, Data, sizeof(Data));
+       UnFreezeRegsT(state);
+
+        reg = (Data[0] << 8) | Data[1];
+        if (reg > 4996)
+               reg = 4996;
+
+        *SignalToNoise = (Log10x100(reg) - Log10x100(5350 - reg)) + 285;
+}
+
+static void GetSignalToNoiseC(struct cxd_state *state, u32 *SignalToNoise)
+{
+       u8 Data[2];
+       u8 Constellation = 0;
+       u32 reg;
+
+       *SignalToNoise = 0;
+       
+       FreezeRegsT(state);
+       readregst_unlocked(state, 0x40, 0x19, &Constellation, 1);
+       readregst_unlocked(state, 0x40, 0x4C, Data, sizeof(Data));
+       UnFreezeRegsT(state);
+
+       reg = ((u32)(Data[0] & 0x1F) << 8) | (Data[1]);
+       if (reg == 0) 
+               return;
+
+        switch (Constellation & 0x07) {
+       case 0: // QAM 16
+       case 2: // QAM 64
+       case 4: // QAM 256
+                if (reg < 126)
+                       reg = 126;
+                *SignalToNoise = ((439 - Log10x100(reg)) * 2134 + 500) / 1000;
+                break;
+       case 1: // QAM 32
+       case 3: // QAM 128
+                if (reg < 69)
+                       reg = 69;
+                *SignalToNoise = ((432 - Log10x100(reg)) * 2015 + 500) / 1000;
+                break;
+        }
+}
+
+static int read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct cxd_state *state = fe->demodulator_priv;
+       u32 SNR = 0;
+
+       *snr = 0;
+       if (state->last_status != 0x1f)
+               return 0;       
+
+       switch (state->state) {
+        case ActiveC:
+               GetSignalToNoiseC(state, &SNR);
+               break;
+        case ActiveC2:
+               GetSignalToNoiseC2(state, &SNR);
+               break;
+        case ActiveT:
+               GetSignalToNoiseT(state, &SNR);
+               break;
+        case ActiveT2:
+               GetSignalToNoiseT2(state, &SNR);
+               break;
+        case ActiveIT:
+               GetSignalToNoiseIT(state, &SNR);
+               break;
+       default:
+               break;
+       }
+       *snr = SNR;
+       return 0;
+}
+
+static int read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       *ucblocks = 0;
+       return 0;
+}
+
+static struct dvb_frontend_ops common_ops_2843 = {
+       .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2, SYS_DVBC2 },
+       .info = {
+               .name = "CXD2843 DVB-C/C2 DVB-T/T2",
+               .frequency_stepsize = 166667,   /* DVB-T only */
+               .frequency_min = 47000000,      /* DVB-T: 47125000 */
+               .frequency_max = 865000000,     /* DVB-C: 862000000 */
+               .symbol_rate_min = 870000,
+               .symbol_rate_max = 11700000,
+               .caps = /* DVB-C */
+                       FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+                       FE_CAN_QAM_128 | FE_CAN_QAM_256 |
+                       FE_CAN_FEC_AUTO |
+                       /* DVB-T */
+                       FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO |
+                       FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO |
+                       FE_CAN_RECOVER | FE_CAN_MUTE_TS
+       },
+       .release = release,
+       .i2c_gate_ctrl = gate_ctrl,
+       .set_frontend = set_parameters,
+
+       .get_tune_settings = get_tune_settings,
+       .read_status = read_status,
+       .read_ber = read_ber,
+       .read_signal_strength = read_signal_strength,
+       .read_snr = read_snr,
+       .read_ucblocks = read_ucblocks,
+};
+
+static struct dvb_frontend_ops common_ops_2837 = {
+       .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2},
+       .info = {
+               .name = "CXD2837 DVB-C DVB-T/T2",
+               .frequency_stepsize = 166667,   /* DVB-T only */
+               .frequency_min = 47000000,      /* DVB-T: 47125000 */
+               .frequency_max = 865000000,     /* DVB-C: 862000000 */
+               .symbol_rate_min = 870000,
+               .symbol_rate_max = 11700000,
+               .caps = /* DVB-C */
+                       FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+                       FE_CAN_QAM_128 | FE_CAN_QAM_256 |
+                       FE_CAN_FEC_AUTO |
+                       /* DVB-T */
+                       FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO |
+                       FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO |
+                       FE_CAN_RECOVER | FE_CAN_MUTE_TS
+       },
+       .release = release,
+       .i2c_gate_ctrl = gate_ctrl,
+       .set_frontend = set_parameters,
+
+       .get_tune_settings = get_tune_settings,
+       .read_status = read_status,
+       .read_ber = read_ber,
+       .read_signal_strength = read_signal_strength,
+       .read_snr = read_snr,
+       .read_ucblocks = read_ucblocks,
+};
+
+static struct dvb_frontend_ops common_ops_2838 = {
+       .delsys = { SYS_ISDBT },
+       .info = {
+               .name = "CXD2838 ISDB-T",
+               .frequency_stepsize = 166667,
+               .frequency_min = 47000000,
+               .frequency_max = 865000000,
+               .symbol_rate_min = 870000,
+               .symbol_rate_max = 11700000,
+               .caps = FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO |
+                       FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO |
+                       FE_CAN_RECOVER | FE_CAN_MUTE_TS
+       },
+       .release = release,
+       .i2c_gate_ctrl = gate_ctrl,
+       .set_frontend = set_parameters,
+
+       .get_tune_settings = get_tune_settings,
+       .read_status = read_status,
+       .read_ber = read_ber,
+       .read_signal_strength = read_signal_strength,
+       .read_snr = read_snr,
+       .read_ucblocks = read_ucblocks,
+};
+
+static int probe(struct cxd_state *state)
+{
+        u8 ChipID = 0x00;
+       int status;
+
+        status = readregst(state, 0x00, 0xFD, &ChipID, 1);
+
+        if (status) {
+               status = readregsx(state, 0x00, 0xFD, &ChipID, 1);
+        }
+        if (status) 
+               return status;
+
+        //printk("ChipID  = %02X\n", ChipID);
+       switch (ChipID) {
+       case 0xa4:
+               state->type = CXD2843;
+               memcpy(&state->frontend.ops, &common_ops_2843, sizeof(struct 
dvb_frontend_ops));
+               break;
+       case 0xb1:
+               state->type = CXD2837;
+               memcpy(&state->frontend.ops, &common_ops_2837, sizeof(struct 
dvb_frontend_ops));
+               break;
+       case 0xb0:
+               state->type = CXD2838;
+               memcpy(&state->frontend.ops, &common_ops_2838, sizeof(struct 
dvb_frontend_ops));
+               break;
+       default:
+               return -1;
+       }
+       state->frontend.demodulator_priv = state;
+       return 0;
+}
+
+struct dvb_frontend *cxd2843_attach(struct i2c_adapter *i2c, struct 
cxd2843_cfg *cfg)
+{
+       struct cxd_state *state = NULL;
+
+       state = kzalloc(sizeof(struct cxd_state), GFP_KERNEL);
+       if (!state)
+               return NULL;
+
+       state->i2c = i2c;
+       init_state(state, cfg);
+       if (probe(state) == 0) {
+               init(state);
+               return &state->frontend;
+       }
+       printk("cxd2843: not found\n");
+       kfree(state);
+       return NULL;
+}
+
+MODULE_DESCRIPTION("CXD2843/37/38 driver");
+MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(cxd2843_attach);
+
diff --git a/drivers/media/dvb-frontends/cxd2843.h 
b/drivers/media/dvb-frontends/cxd2843.h
new file mode 100644
index 0000000..b6bbc90
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2843.h
@@ -0,0 +1,47 @@
+/*
+ *  cxd2843.h: Driver for the Sony CXD2843ER DVB-T/T2/C/C2 demodulator.
+ *             Also supports the CXD2837ER DVB-T/T2/C and the CXD2838ER
+ *             ISDB-T demodulator.
+ *
+ *  Copyright (C) 2010-2013 Digital Devices GmbH
+ *  Copyright (C) 2013 Maik Broemme <mbroe...@parallels.com>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  version 2 only, 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA
+ */
+
+#ifndef _CXD2843_H_
+#define _CXD2843_H_
+
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+struct cxd2843_cfg {
+       u8  adr;
+       u32 ts_clock;
+};
+
+#if IS_ENABLED(CONFIG_DVB_CXD2843)
+struct dvb_frontend *cxd2843_attach(struct i2c_adapter *i2c,
+                                   struct cxd2843_cfg *cfg);
+#else
+static inline struct dvb_frontend *cxd2843_attach(struct i2c_adapter *i2c,
+                                                 struct cxd2843_cfg *cfg);
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif
-- 
1.8.4.2
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to