Merge branch 'mantis' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 18 Jan 2010 22:07:07 +0000 (14:07 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 18 Jan 2010 22:07:07 +0000 (14:07 -0800)
* 'mantis' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (117 commits)
  V4L/DVB (13851): Fix Input dependency for Mantis
  V4L/DVB(13824a): mantis: Fix __devexit bad annotations
  V4L/DVB (13808b): mantis: replace DMA_nnBIT_MASK to DMA_BIT_MASK(32)
  V4L/DVB (13808): [Mantis/Hopper] Build update for Mantis/Hopper based cards
  V4L/DVB(13808a): mantis: convert it to the new ir-core register/unregister functions
  V4L/DVB (13812): [Mantis/Hopper] Update Copyright header
  V4L/DVB (13811): [MB86A16] Update Copyright header
  V4L/DVB (13810): [MB86A16] Use DVB_* macros
  V4L/DVB (13809): Fix Checkpatch violations
  V4L/DVB (13807): Fix: Free device in the device registration failure case
  V4L/DVB (13806): Register and Initialize Remote control
  V4L/DVB (13805): Fix: Unregister the frontend before detaching
  V4L/DVB (13804): Remove unused I2C Adapter ID
  V4L/DVB (13803): Remove unused dependency on CU1216
  V4L/DVB (13802): [Mantis/Hopper] Fix all build related warnings
  V4L/DVB (13801): [MB86A16] Use the search callback
  V4L/DVB (13800): [Mantis] I2C optimization. Required delay is much lesser than 1mS.
  V4L/DVB (13799): [Mantis] Unregister frontend
  V4L/DVB (13798): [Mantis] Enable power for all cards, use byte mode only on relevant devices
  V4L/DVB (13797): [Mantis/Hopper/TDA665x] Large overhaul,
  ...

54 files changed:
drivers/media/dvb/Kconfig
drivers/media/dvb/Makefile
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/mb86a16.c [new file with mode: 0644]
drivers/media/dvb/frontends/mb86a16.h [new file with mode: 0644]
drivers/media/dvb/frontends/mb86a16_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda10021.c
drivers/media/dvb/frontends/tda665x.c [new file with mode: 0644]
drivers/media/dvb/frontends/tda665x.h [new file with mode: 0644]
drivers/media/dvb/mantis/Kconfig [new file with mode: 0644]
drivers/media/dvb/mantis/Makefile [new file with mode: 0644]
drivers/media/dvb/mantis/hopper_cards.c [new file with mode: 0644]
drivers/media/dvb/mantis/hopper_vp3028.c [new file with mode: 0644]
drivers/media/dvb/mantis/hopper_vp3028.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_ca.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_ca.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_cards.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_common.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_core.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_core.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_dma.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_dma.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_dvb.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_dvb.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_evm.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_hif.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_hif.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_i2c.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_i2c.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_input.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_ioc.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_ioc.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_link.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_pci.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_pci.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_pcmcia.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_reg.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_uart.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_uart.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_vp1033.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_vp1033.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_vp1034.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_vp1034.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_vp1041.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_vp1041.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_vp2033.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_vp2033.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_vp2040.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_vp2040.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_vp3028.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_vp3028.h [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_vp3030.c [new file with mode: 0644]
drivers/media/dvb/mantis/mantis_vp3030.h [new file with mode: 0644]

index 35d0817126e9fc65a67aa20ca5f2490e30a7dc70..cf8f65f309da8ecd95b5d93a394e26ef3baa14f7 100644 (file)
@@ -72,6 +72,10 @@ comment "Supported Earthsoft PT1 Adapters"
        depends on DVB_CORE && PCI && I2C
 source "drivers/media/dvb/pt1/Kconfig"
 
+comment "Supported Mantis Adapters"
+       depends on DVB_CORE && PCI && I2C
+       source "drivers/media/dvb/mantis/Kconfig"
+
 comment "Supported DVB Frontends"
        depends on DVB_CORE
 source "drivers/media/dvb/frontends/Kconfig"
index 16d262ddb45d1bce7b4e2402d896187e053490a8..c12922c3659b221b9e9456259cab4977bad53950 100644 (file)
@@ -2,6 +2,18 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
-obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/ pt1/
+obj-y        := dvb-core/      \
+               frontends/      \
+               ttpci/          \
+               ttusb-dec/      \
+               ttusb-budget/   \
+               b2c2/           \
+               bt8xx/          \
+               dvb-usb/        \
+               pluto2/         \
+               siano/          \
+               dm1105/         \
+               pt1/            \
+               mantis/
 
 obj-$(CONFIG_DVB_FIREDTV)      += firewire/
index a3b8b697349b130f161daf1dc747d40c89ffcdb7..cd7f9b7cbffabad65972ca372b03e6830c19b7a4 100644 (file)
@@ -208,6 +208,14 @@ config DVB_DS3000
        help
          A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
 
+config DVB_MB86A16
+       tristate "Fujitsu MB86A16 based"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-S/DSS Direct Conversion reveiver.
+         Say Y when you want to support this frontend.
+
 comment "DVB-T (terrestrial) frontends"
        depends on DVB_CORE
 
@@ -587,6 +595,17 @@ config DVB_ATBM8830
        help
          A DMB-TH tuner module. Say Y when you want to support this frontend.
 
+config DVB_TDA665x
+       tristate "TDA665x tuner"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         Support for tuner modules based on Philips TDA6650/TDA6651 chips.
+         Say Y when you want to support this chip.
+
+         Currently supported tuners:
+         * Panasonic ENV57H12D5 (ET-50DT)
+
 comment "Tools to develop new frontends"
 
 config DVB_DUMMY_FE
index 47575cc7b699cea3a431b6d1c29093847402a5e8..874e8ada4d1dbec59bc089314213bcf1beadf920 100644 (file)
@@ -64,6 +64,7 @@ obj-$(CONFIG_DVB_TDA10048) += tda10048.o
 obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
 obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
 obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
+obj-$(CONFIG_DVB_TDA665x) += tda665x.o
 obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
 obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o
 obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
@@ -80,3 +81,4 @@ obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
 obj-$(CONFIG_DVB_ISL6423) += isl6423.o
 obj-$(CONFIG_DVB_EC100) += ec100.o
 obj-$(CONFIG_DVB_DS3000) += ds3000.o
+obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
diff --git a/drivers/media/dvb/frontends/mb86a16.c b/drivers/media/dvb/frontends/mb86a16.c
new file mode 100644 (file)
index 0000000..d05f750
--- /dev/null
@@ -0,0 +1,1878 @@
+/*
+       Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include "dvb_frontend.h"
+#include "mb86a16.h"
+#include "mb86a16_priv.h"
+
+unsigned int verbose = 5;
+module_param(verbose, int, 0644);
+
+#define ABS(x)         ((x) < 0 ? (-x) : (x))
+
+struct mb86a16_state {
+       struct i2c_adapter              *i2c_adap;
+       const struct mb86a16_config     *config;
+       struct dvb_frontend             frontend;
+
+       /* tuning parameters */
+       int                             frequency;
+       int                             srate;
+
+       /* Internal stuff */
+       int                             master_clk;
+       int                             deci;
+       int                             csel;
+       int                             rsel;
+};
+
+#define MB86A16_ERROR          0
+#define MB86A16_NOTICE         1
+#define MB86A16_INFO           2
+#define MB86A16_DEBUG          3
+
+#define dprintk(x, y, z, format, arg...) do {                                          \
+       if (z) {                                                                        \
+               if      ((x > MB86A16_ERROR) && (x > y))                                \
+                       printk(KERN_ERR "%s: " format "\n", __func__, ##arg);           \
+               else if ((x > MB86A16_NOTICE) && (x > y))                               \
+                       printk(KERN_NOTICE "%s: " format "\n", __func__, ##arg);        \
+               else if ((x > MB86A16_INFO) && (x > y))                                 \
+                       printk(KERN_INFO "%s: " format "\n", __func__, ##arg);          \
+               else if ((x > MB86A16_DEBUG) && (x > y))                                \
+                       printk(KERN_DEBUG "%s: " format "\n", __func__, ##arg);         \
+       } else {                                                                        \
+               if (x > y)                                                              \
+                       printk(format, ##arg);                                          \
+       }                                                                               \
+} while (0)
+
+#define TRACE_IN       dprintk(verbose, MB86A16_DEBUG, 1, "-->()")
+#define TRACE_OUT      dprintk(verbose, MB86A16_DEBUG, 1, "()-->")
+
+static int mb86a16_write(struct mb86a16_state *state, u8 reg, u8 val)
+{
+       int ret;
+       u8 buf[] = { reg, val };
+
+       struct i2c_msg msg = {
+               .addr = state->config->demod_address,
+               .flags = 0,
+               .buf = buf,
+               .len = 2
+       };
+
+       dprintk(verbose, MB86A16_DEBUG, 1,
+               "writing to [0x%02x],Reg[0x%02x],Data[0x%02x]",
+               state->config->demod_address, buf[0], buf[1]);
+
+       ret = i2c_transfer(state->i2c_adap, &msg, 1);
+
+       return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int mb86a16_read(struct mb86a16_state *state, u8 reg, u8 *val)
+{
+       int ret;
+       u8 b0[] = { reg };
+       u8 b1[] = { 0 };
+
+       struct i2c_msg msg[] = {
+               {
+                       .addr = state->config->demod_address,
+                       .flags = 0,
+                       .buf = b0,
+                       .len = 1
+               }, {
+                       .addr = state->config->demod_address,
+                       .flags = I2C_M_RD,
+                       .buf = b1,
+                       .len = 1
+               }
+       };
+       ret = i2c_transfer(state->i2c_adap, msg, 2);
+       if (ret != 2) {
+               dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=0x%i)",
+                       reg, ret);
+
+               return -EREMOTEIO;
+       }
+       *val = b1[0];
+
+       return ret;
+}
+
+static int CNTM_set(struct mb86a16_state *state,
+                   unsigned char timint1,
+                   unsigned char timint2,
+                   unsigned char cnext)
+{
+       unsigned char val;
+
+       val = (timint1 << 4) | (timint2 << 2) | cnext;
+       if (mb86a16_write(state, MB86A16_CNTMR, val) < 0)
+               goto err;
+
+       return 0;
+
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static int smrt_set(struct mb86a16_state *state, int rate)
+{
+       int tmp ;
+       int m ;
+       unsigned char STOFS0, STOFS1;
+
+       m = 1 << state->deci;
+       tmp = (8192 * state->master_clk - 2 * m * rate * 8192 + state->master_clk / 2) / state->master_clk;
+
+       STOFS0 = tmp & 0x0ff;
+       STOFS1 = (tmp & 0xf00) >> 8;
+
+       if (mb86a16_write(state, MB86A16_SRATE1, (state->deci << 2) |
+                                      (state->csel << 1) |
+                                       state->rsel) < 0)
+               goto err;
+       if (mb86a16_write(state, MB86A16_SRATE2, STOFS0) < 0)
+               goto err;
+       if (mb86a16_write(state, MB86A16_SRATE3, STOFS1) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -1;
+}
+
+static int srst(struct mb86a16_state *state)
+{
+       if (mb86a16_write(state, MB86A16_RESET, 0x04) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+
+}
+
+static int afcex_data_set(struct mb86a16_state *state,
+                         unsigned char AFCEX_L,
+                         unsigned char AFCEX_H)
+{
+       if (mb86a16_write(state, MB86A16_AFCEXL, AFCEX_L) < 0)
+               goto err;
+       if (mb86a16_write(state, MB86A16_AFCEXH, AFCEX_H) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+
+       return -1;
+}
+
+static int afcofs_data_set(struct mb86a16_state *state,
+                          unsigned char AFCEX_L,
+                          unsigned char AFCEX_H)
+{
+       if (mb86a16_write(state, 0x58, AFCEX_L) < 0)
+               goto err;
+       if (mb86a16_write(state, 0x59, AFCEX_H) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static int stlp_set(struct mb86a16_state *state,
+                   unsigned char STRAS,
+                   unsigned char STRBS)
+{
+       if (mb86a16_write(state, MB86A16_STRFILTCOEF1, (STRBS << 3) | (STRAS)) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static int Vi_set(struct mb86a16_state *state, unsigned char ETH, unsigned char VIA)
+{
+       if (mb86a16_write(state, MB86A16_VISET2, 0x04) < 0)
+               goto err;
+       if (mb86a16_write(state, MB86A16_VISET3, 0xf5) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static int initial_set(struct mb86a16_state *state)
+{
+       if (stlp_set(state, 5, 7))
+               goto err;
+
+       udelay(100);
+       if (afcex_data_set(state, 0, 0))
+               goto err;
+
+       udelay(100);
+       if (afcofs_data_set(state, 0, 0))
+               goto err;
+
+       udelay(100);
+       if (mb86a16_write(state, MB86A16_CRLFILTCOEF1, 0x16) < 0)
+               goto err;
+       if (mb86a16_write(state, 0x2f, 0x21) < 0)
+               goto err;
+       if (mb86a16_write(state, MB86A16_VIMAG, 0x38) < 0)
+               goto err;
+       if (mb86a16_write(state, MB86A16_FAGCS1, 0x00) < 0)
+               goto err;
+       if (mb86a16_write(state, MB86A16_FAGCS2, 0x1c) < 0)
+               goto err;
+       if (mb86a16_write(state, MB86A16_FAGCS3, 0x20) < 0)
+               goto err;
+       if (mb86a16_write(state, MB86A16_FAGCS4, 0x1e) < 0)
+               goto err;
+       if (mb86a16_write(state, MB86A16_FAGCS5, 0x23) < 0)
+               goto err;
+       if (mb86a16_write(state, 0x54, 0xff) < 0)
+               goto err;
+       if (mb86a16_write(state, MB86A16_TSOUT, 0x00) < 0)
+               goto err;
+
+       return 0;
+
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static int S01T_set(struct mb86a16_state *state,
+                   unsigned char s1t,
+                   unsigned s0t)
+{
+       if (mb86a16_write(state, 0x33, (s1t << 3) | s0t) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+
+static int EN_set(struct mb86a16_state *state,
+                 int cren,
+                 int afcen)
+{
+       unsigned char val;
+
+       val = 0x7a | (cren << 7) | (afcen << 2);
+       if (mb86a16_write(state, 0x49, val) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static int AFCEXEN_set(struct mb86a16_state *state,
+                      int afcexen,
+                      int smrt)
+{
+       unsigned char AFCA ;
+
+       if (smrt > 18875)
+               AFCA = 4;
+       else if (smrt > 9375)
+               AFCA = 3;
+       else if (smrt > 2250)
+               AFCA = 2;
+       else
+               AFCA = 1;
+
+       if (mb86a16_write(state, 0x2a, 0x02 | (afcexen << 5) | (AFCA << 2)) < 0)
+               goto err;
+
+       return 0;
+
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static int DAGC_data_set(struct mb86a16_state *state,
+                        unsigned char DAGCA,
+                        unsigned char DAGCW)
+{
+       if (mb86a16_write(state, 0x2d, (DAGCA << 3) | DAGCW) < 0)
+               goto err;
+
+       return 0;
+
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static void smrt_info_get(struct mb86a16_state *state, int rate)
+{
+       if (rate >= 37501) {
+               state->deci = 0; state->csel = 0; state->rsel = 0;
+       } else if (rate >= 30001) {
+               state->deci = 0; state->csel = 0; state->rsel = 1;
+       } else if (rate >= 26251) {
+               state->deci = 0; state->csel = 1; state->rsel = 0;
+       } else if (rate >= 22501) {
+               state->deci = 0; state->csel = 1; state->rsel = 1;
+       } else if (rate >= 18751) {
+               state->deci = 1; state->csel = 0; state->rsel = 0;
+       } else if (rate >= 15001) {
+               state->deci = 1; state->csel = 0; state->rsel = 1;
+       } else if (rate >= 13126) {
+               state->deci = 1; state->csel = 1; state->rsel = 0;
+       } else if (rate >= 11251) {
+               state->deci = 1; state->csel = 1; state->rsel = 1;
+       } else if (rate >= 9376) {
+               state->deci = 2; state->csel = 0; state->rsel = 0;
+       } else if (rate >= 7501) {
+               state->deci = 2; state->csel = 0; state->rsel = 1;
+       } else if (rate >= 6563) {
+               state->deci = 2; state->csel = 1; state->rsel = 0;
+       } else if (rate >= 5626) {
+               state->deci = 2; state->csel = 1; state->rsel = 1;
+       } else if (rate >= 4688) {
+               state->deci = 3; state->csel = 0; state->rsel = 0;
+       } else if (rate >= 3751) {
+               state->deci = 3; state->csel = 0; state->rsel = 1;
+       } else if (rate >= 3282) {
+               state->deci = 3; state->csel = 1; state->rsel = 0;
+       } else if (rate >= 2814) {
+               state->deci = 3; state->csel = 1; state->rsel = 1;
+       } else if (rate >= 2344) {
+               state->deci = 4; state->csel = 0; state->rsel = 0;
+       } else if (rate >= 1876) {
+               state->deci = 4; state->csel = 0; state->rsel = 1;
+       } else if (rate >= 1641) {
+               state->deci = 4; state->csel = 1; state->rsel = 0;
+       } else if (rate >= 1407) {
+               state->deci = 4; state->csel = 1; state->rsel = 1;
+       } else if (rate >= 1172) {
+               state->deci = 5; state->csel = 0; state->rsel = 0;
+       } else if (rate >=  939) {
+               state->deci = 5; state->csel = 0; state->rsel = 1;
+       } else if (rate >=  821) {
+               state->deci = 5; state->csel = 1; state->rsel = 0;
+       } else {
+               state->deci = 5; state->csel = 1; state->rsel = 1;
+       }
+
+       if (state->csel == 0)
+               state->master_clk = 92000;
+       else
+               state->master_clk = 61333;
+
+}
+
+static int signal_det(struct mb86a16_state *state,
+                     int smrt,
+                     unsigned char *SIG)
+{
+
+       int ret ;
+       int smrtd ;
+       int wait_sym ;
+
+       u32 wait_t;
+       unsigned char S[3] ;
+       int i ;
+
+       if (*SIG > 45) {
+               if (CNTM_set(state, 2, 1, 2) < 0) {
+                       dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
+                       return -1;
+               }
+               wait_sym = 40000;
+       } else {
+               if (CNTM_set(state, 3, 1, 2) < 0) {
+                       dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
+                       return -1;
+               }
+               wait_sym = 80000;
+       }
+       for (i = 0; i < 3; i++) {
+               if (i == 0)
+                       smrtd = smrt * 98 / 100;
+               else if (i == 1)
+                       smrtd = smrt;
+               else
+                       smrtd = smrt * 102 / 100;
+               smrt_info_get(state, smrtd);
+               smrt_set(state, smrtd);
+               srst(state);
+               wait_t = (wait_sym + 99 * smrtd / 100) / smrtd;
+               if (wait_t == 0)
+                       wait_t = 1;
+               msleep_interruptible(10);
+               if (mb86a16_read(state, 0x37, &(S[i])) != 2) {
+                       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+                       return -EREMOTEIO;
+               }
+       }
+       if ((S[1] > S[0] * 112 / 100) &&
+           (S[1] > S[2] * 112 / 100)) {
+
+               ret = 1;
+       } else {
+               ret = 0;
+       }
+       *SIG = S[1];
+
+       if (CNTM_set(state, 0, 1, 2) < 0) {
+               dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
+               return -1;
+       }
+
+       return ret;
+}
+
+static int rf_val_set(struct mb86a16_state *state,
+                     int f,
+                     int smrt,
+                     unsigned char R)
+{
+       unsigned char C, F, B;
+       int M;
+       unsigned char rf_val[5];
+       int ack = -1;
+
+       if (smrt > 37750)
+               C = 1;
+       else if (smrt > 18875)
+               C = 2;
+       else if (smrt > 5500)
+               C = 3;
+       else
+               C = 4;
+
+       if (smrt > 30500)
+               F = 3;
+       else if (smrt > 9375)
+               F = 1;
+       else if (smrt > 4625)
+               F = 0;
+       else
+               F = 2;
+
+       if (f < 1060)
+               B = 0;
+       else if (f < 1175)
+               B = 1;
+       else if (f < 1305)
+               B = 2;
+       else if (f < 1435)
+               B = 3;
+       else if (f < 1570)
+               B = 4;
+       else if (f < 1715)
+               B = 5;
+       else if (f < 1845)
+               B = 6;
+       else if (f < 1980)
+               B = 7;
+       else if (f < 2080)
+               B = 8;
+       else
+               B = 9;
+
+       M = f * (1 << R) / 2;
+
+       rf_val[0] = 0x01 | (C << 3) | (F << 1);
+       rf_val[1] = (R << 5) | ((M & 0x1f000) >> 12);
+       rf_val[2] = (M & 0x00ff0) >> 4;
+       rf_val[3] = ((M & 0x0000f) << 4) | B;
+
+       /* Frequency Set */
+       if (mb86a16_write(state, 0x21, rf_val[0]) < 0)
+               ack = 0;
+       if (mb86a16_write(state, 0x22, rf_val[1]) < 0)
+               ack = 0;
+       if (mb86a16_write(state, 0x23, rf_val[2]) < 0)
+               ack = 0;
+       if (mb86a16_write(state, 0x24, rf_val[3]) < 0)
+               ack = 0;
+       if (mb86a16_write(state, 0x25, 0x01) < 0)
+               ack = 0;
+       if (ack == 0) {
+               dprintk(verbose, MB86A16_ERROR, 1, "RF Setup - I2C transfer error");
+               return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+static int afcerr_chk(struct mb86a16_state *state)
+{
+       unsigned char AFCM_L, AFCM_H ;
+       int AFCM ;
+       int afcm, afcerr ;
+
+       if (mb86a16_read(state, 0x0e, &AFCM_L) != 2)
+               goto err;
+       if (mb86a16_read(state, 0x0f, &AFCM_H) != 2)
+               goto err;
+
+       AFCM = (AFCM_H << 8) + AFCM_L;
+
+       if (AFCM > 2048)
+               afcm = AFCM - 4096;
+       else
+               afcm = AFCM;
+       afcerr = afcm * state->master_clk / 8192;
+
+       return afcerr;
+
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static int dagcm_val_get(struct mb86a16_state *state)
+{
+       int DAGCM;
+       unsigned char DAGCM_H, DAGCM_L;
+
+       if (mb86a16_read(state, 0x45, &DAGCM_L) != 2)
+               goto err;
+       if (mb86a16_read(state, 0x46, &DAGCM_H) != 2)
+               goto err;
+
+       DAGCM = (DAGCM_H << 8) + DAGCM_L;
+
+       return DAGCM;
+
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static int mb86a16_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       u8 stat, stat2;
+       struct mb86a16_state *state = fe->demodulator_priv;
+
+       *status = 0;
+
+       if (mb86a16_read(state, MB86A16_SIG1, &stat) != 2)
+               goto err;
+       if (mb86a16_read(state, MB86A16_SIG2, &stat2) != 2)
+               goto err;
+       if ((stat > 25) && (stat2 > 25))
+               *status |= FE_HAS_SIGNAL;
+       if ((stat > 45) && (stat2 > 45))
+               *status |= FE_HAS_CARRIER;
+
+       if (mb86a16_read(state, MB86A16_STATUS, &stat) != 2)
+               goto err;
+
+       if (stat & 0x01)
+               *status |= FE_HAS_SYNC;
+       if (stat & 0x01)
+               *status |= FE_HAS_VITERBI;
+
+       if (mb86a16_read(state, MB86A16_FRAMESYNC, &stat) != 2)
+               goto err;
+
+       if ((stat & 0x0f) && (*status & FE_HAS_VITERBI))
+               *status |= FE_HAS_LOCK;
+
+       return 0;
+
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static int sync_chk(struct mb86a16_state *state,
+                   unsigned char *VIRM)
+{
+       unsigned char val;
+       int sync;
+
+       if (mb86a16_read(state, 0x0d, &val) != 2)
+               goto err;
+
+       dprintk(verbose, MB86A16_INFO, 1, "Status = %02x,", val);
+       sync = val & 0x01;
+       *VIRM = (val & 0x1c) >> 2;
+
+       return sync;
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+
+}
+
+static int freqerr_chk(struct mb86a16_state *state,
+                      int fTP,
+                      int smrt,
+                      int unit)
+{
+       unsigned char CRM, AFCML, AFCMH;
+       unsigned char temp1, temp2, temp3;
+       int crm, afcm, AFCM;
+       int crrerr, afcerr;             /* kHz */
+       int frqerr;                     /* MHz */
+       int afcen, afcexen = 0;
+       int R, M, fOSC, fOSC_OFS;
+
+       if (mb86a16_read(state, 0x43, &CRM) != 2)
+               goto err;
+
+       if (CRM > 127)
+               crm = CRM - 256;
+       else
+               crm = CRM;
+
+       crrerr = smrt * crm / 256;
+       if (mb86a16_read(state, 0x49, &temp1) != 2)
+               goto err;
+
+       afcen = (temp1 & 0x04) >> 2;
+       if (afcen == 0) {
+               if (mb86a16_read(state, 0x2a, &temp1) != 2)
+                       goto err;
+               afcexen = (temp1 & 0x20) >> 5;
+       }
+
+       if (afcen == 1) {
+               if (mb86a16_read(state, 0x0e, &AFCML) != 2)
+                       goto err;
+               if (mb86a16_read(state, 0x0f, &AFCMH) != 2)
+                       goto err;
+       } else if (afcexen == 1) {
+               if (mb86a16_read(state, 0x2b, &AFCML) != 2)
+                       goto err;
+               if (mb86a16_read(state, 0x2c, &AFCMH) != 2)
+                       goto err;
+       }
+       if ((afcen == 1) || (afcexen == 1)) {
+               smrt_info_get(state, smrt);
+               AFCM = ((AFCMH & 0x01) << 8) + AFCML;
+               if (AFCM > 255)
+                       afcm = AFCM - 512;
+               else
+                       afcm = AFCM;
+
+               afcerr = afcm * state->master_clk / 8192;
+       } else
+               afcerr = 0;
+
+       if (mb86a16_read(state, 0x22, &temp1) != 2)
+               goto err;
+       if (mb86a16_read(state, 0x23, &temp2) != 2)
+               goto err;
+       if (mb86a16_read(state, 0x24, &temp3) != 2)
+               goto err;
+
+       R = (temp1 & 0xe0) >> 5;
+       M = ((temp1 & 0x1f) << 12) + (temp2 << 4) + (temp3 >> 4);
+       if (R == 0)
+               fOSC = 2 * M;
+       else
+               fOSC = M;
+
+       fOSC_OFS = fOSC - fTP;
+
+       if (unit == 0) {        /* MHz */
+               if (crrerr + afcerr + fOSC_OFS * 1000 >= 0)
+                       frqerr = (crrerr + afcerr + fOSC_OFS * 1000 + 500) / 1000;
+               else
+                       frqerr = (crrerr + afcerr + fOSC_OFS * 1000 - 500) / 1000;
+       } else {        /* kHz */
+               frqerr = crrerr + afcerr + fOSC_OFS * 1000;
+       }
+
+       return frqerr;
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static unsigned char vco_dev_get(struct mb86a16_state *state, int smrt)
+{
+       unsigned char R;
+
+       if (smrt > 9375)
+               R = 0;
+       else
+               R = 1;
+
+       return R;
+}
+
+static void swp_info_get(struct mb86a16_state *state,
+                        int fOSC_start,
+                        int smrt,
+                        int v, int R,
+                        int swp_ofs,
+                        int *fOSC,
+                        int *afcex_freq,
+                        unsigned char *AFCEX_L,
+                        unsigned char *AFCEX_H)
+{
+       int AFCEX ;
+       int crnt_swp_freq ;
+
+       crnt_swp_freq = fOSC_start * 1000 + v * swp_ofs;
+
+       if (R == 0)
+               *fOSC = (crnt_swp_freq + 1000) / 2000 * 2;
+       else
+               *fOSC = (crnt_swp_freq + 500) / 1000;
+
+       if (*fOSC >= crnt_swp_freq)
+               *afcex_freq = *fOSC * 1000 - crnt_swp_freq;
+       else
+               *afcex_freq = crnt_swp_freq - *fOSC * 1000;
+
+       AFCEX = *afcex_freq * 8192 / state->master_clk;
+       *AFCEX_L =  AFCEX & 0x00ff;
+       *AFCEX_H = (AFCEX & 0x0f00) >> 8;
+}
+
+
+static int swp_freq_calcuation(struct mb86a16_state *state, int i, int v, int *V,  int vmax, int vmin,
+                              int SIGMIN, int fOSC, int afcex_freq, int swp_ofs, unsigned char *SIG1)
+{
+       int swp_freq ;
+
+       if ((i % 2 == 1) && (v <= vmax)) {
+               /* positive v (case 1) */
+               if ((v - 1 == vmin)                             &&
+                   (*(V + 30 + v) >= 0)                        &&
+                   (*(V + 30 + v - 1) >= 0)                    &&
+                   (*(V + 30 + v - 1) > *(V + 30 + v))         &&
+                   (*(V + 30 + v - 1) > SIGMIN)) {
+
+                       swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
+                       *SIG1 = *(V + 30 + v - 1);
+               } else if ((v == vmax)                          &&
+                          (*(V + 30 + v) >= 0)                 &&
+                          (*(V + 30 + v - 1) >= 0)             &&
+                          (*(V + 30 + v) > *(V + 30 + v - 1))  &&
+                          (*(V + 30 + v) > SIGMIN)) {
+                       /* (case 2) */
+                       swp_freq = fOSC * 1000 + afcex_freq;
+                       *SIG1 = *(V + 30 + v);
+               } else if ((*(V + 30 + v) > 0)                  &&
+                          (*(V + 30 + v - 1) > 0)              &&
+                          (*(V + 30 + v - 2) > 0)              &&
+                          (*(V + 30 + v - 3) > 0)              &&
+                          (*(V + 30 + v - 1) > *(V + 30 + v))  &&
+                          (*(V + 30 + v - 2) > *(V + 30 + v - 3)) &&
+                          ((*(V + 30 + v - 1) > SIGMIN)        ||
+                          (*(V + 30 + v - 2) > SIGMIN))) {
+                       /* (case 3) */
+                       if (*(V + 30 + v - 1) >= *(V + 30 + v - 2)) {
+                               swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
+                               *SIG1 = *(V + 30 + v - 1);
+                       } else {
+                               swp_freq = fOSC * 1000 + afcex_freq - swp_ofs * 2;
+                               *SIG1 = *(V + 30 + v - 2);
+                       }
+               } else if ((v == vmax)                          &&
+                          (*(V + 30 + v) >= 0)                 &&
+                          (*(V + 30 + v - 1) >= 0)             &&
+                          (*(V + 30 + v - 2) >= 0)             &&
+                          (*(V + 30 + v) > *(V + 30 + v - 2))  &&
+                          (*(V + 30 + v - 1) > *(V + 30 + v - 2)) &&
+                          ((*(V + 30 + v) > SIGMIN)            ||
+                          (*(V + 30 + v - 1) > SIGMIN))) {
+                       /* (case 4) */
+                       if (*(V + 30 + v) >= *(V + 30 + v - 1)) {
+                               swp_freq = fOSC * 1000 + afcex_freq;
+                               *SIG1 = *(V + 30 + v);
+                       } else {
+                               swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
+                               *SIG1 = *(V + 30 + v - 1);
+                       }
+               } else  {
+                       swp_freq = -1 ;
+               }
+       } else if ((i % 2 == 0) && (v >= vmin)) {
+               /* Negative v (case 1) */
+               if ((*(V + 30 + v) > 0)                         &&
+                   (*(V + 30 + v + 1) > 0)                     &&
+                   (*(V + 30 + v + 2) > 0)                     &&
+                   (*(V + 30 + v + 1) > *(V + 30 + v))         &&
+                   (*(V + 30 + v + 1) > *(V + 30 + v + 2))     &&
+                   (*(V + 30 + v + 1) > SIGMIN)) {
+
+                       swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+                       *SIG1 = *(V + 30 + v + 1);
+               } else if ((v + 1 == vmax)                      &&
+                          (*(V + 30 + v) >= 0)                 &&
+                          (*(V + 30 + v + 1) >= 0)             &&
+                          (*(V + 30 + v + 1) > *(V + 30 + v))  &&
+                          (*(V + 30 + v + 1) > SIGMIN)) {
+                       /* (case 2) */
+                       swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+                       *SIG1 = *(V + 30 + v);
+               } else if ((v == vmin)                          &&
+                          (*(V + 30 + v) > 0)                  &&
+                          (*(V + 30 + v + 1) > 0)              &&
+                          (*(V + 30 + v + 2) > 0)              &&
+                          (*(V + 30 + v) > *(V + 30 + v + 1))  &&
+                          (*(V + 30 + v) > *(V + 30 + v + 2))  &&
+                          (*(V + 30 + v) > SIGMIN)) {
+                       /* (case 3) */
+                       swp_freq = fOSC * 1000 + afcex_freq;
+                       *SIG1 = *(V + 30 + v);
+               } else if ((*(V + 30 + v) >= 0)                 &&
+                          (*(V + 30 + v + 1) >= 0)             &&
+                          (*(V + 30 + v + 2) >= 0)             &&
+                          (*(V + 30 + v + 3) >= 0)             &&
+                          (*(V + 30 + v + 1) > *(V + 30 + v))  &&
+                          (*(V + 30 + v + 2) > *(V + 30 + v + 3)) &&
+                          ((*(V + 30 + v + 1) > SIGMIN)        ||
+                           (*(V + 30 + v + 2) > SIGMIN))) {
+                       /* (case 4) */
+                       if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) {
+                               swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+                               *SIG1 = *(V + 30 + v + 1);
+                       } else {
+                               swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2;
+                               *SIG1 = *(V + 30 + v + 2);
+                       }
+               } else if ((*(V + 30 + v) >= 0)                 &&
+                          (*(V + 30 + v + 1) >= 0)             &&
+                          (*(V + 30 + v + 2) >= 0)             &&
+                          (*(V + 30 + v + 3) >= 0)             &&
+                          (*(V + 30 + v) > *(V + 30 + v + 2))  &&
+                          (*(V + 30 + v + 1) > *(V + 30 + v + 2)) &&
+                          (*(V + 30 + v) > *(V + 30 + v + 3))  &&
+                          (*(V + 30 + v + 1) > *(V + 30 + v + 3)) &&
+                          ((*(V + 30 + v) > SIGMIN)            ||
+                           (*(V + 30 + v + 1) > SIGMIN))) {
+                       /* (case 5) */
+                       if (*(V + 30 + v) >= *(V + 30 + v + 1)) {
+                               swp_freq = fOSC * 1000 + afcex_freq;
+                               *SIG1 = *(V + 30 + v);
+                       } else {
+                               swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+                               *SIG1 = *(V + 30 + v + 1);
+                       }
+               } else if ((v + 2 == vmin)                      &&
+                          (*(V + 30 + v) >= 0)                 &&
+                          (*(V + 30 + v + 1) >= 0)             &&
+                          (*(V + 30 + v + 2) >= 0)             &&
+                          (*(V + 30 + v + 1) > *(V + 30 + v))  &&
+                          (*(V + 30 + v + 2) > *(V + 30 + v))  &&
+                          ((*(V + 30 + v + 1) > SIGMIN)        ||
+                           (*(V + 30 + v + 2) > SIGMIN))) {
+                       /* (case 6) */
+                       if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) {
+                               swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+                               *SIG1 = *(V + 30 + v + 1);
+                       } else {
+                               swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2;
+                               *SIG1 = *(V + 30 + v + 2);
+                       }
+               } else if ((vmax == 0) && (vmin == 0) && (*(V + 30 + v) > SIGMIN)) {
+                       swp_freq = fOSC * 1000;
+                       *SIG1 = *(V + 30 + v);
+               } else
+                       swp_freq = -1;
+       } else
+               swp_freq = -1;
+
+       return swp_freq;
+}
+
+static void swp_info_get2(struct mb86a16_state *state,
+                         int smrt,
+                         int R,
+                         int swp_freq,
+                         int *afcex_freq,
+                         int *fOSC,
+                         unsigned char *AFCEX_L,
+                         unsigned char *AFCEX_H)
+{
+       int AFCEX ;
+
+       if (R == 0)
+               *fOSC = (swp_freq + 1000) / 2000 * 2;
+       else
+               *fOSC = (swp_freq + 500) / 1000;
+
+       if (*fOSC >= swp_freq)
+               *afcex_freq = *fOSC * 1000 - swp_freq;
+       else
+               *afcex_freq = swp_freq - *fOSC * 1000;
+
+       AFCEX = *afcex_freq * 8192 / state->master_clk;
+       *AFCEX_L =  AFCEX & 0x00ff;
+       *AFCEX_H = (AFCEX & 0x0f00) >> 8;
+}
+
+static void afcex_info_get(struct mb86a16_state *state,
+                          int afcex_freq,
+                          unsigned char *AFCEX_L,
+                          unsigned char *AFCEX_H)
+{
+       int AFCEX ;
+
+       AFCEX = afcex_freq * 8192 / state->master_clk;
+       *AFCEX_L =  AFCEX & 0x00ff;
+       *AFCEX_H = (AFCEX & 0x0f00) >> 8;
+}
+
+static int SEQ_set(struct mb86a16_state *state, unsigned char loop)
+{
+       /* SLOCK0 = 0 */
+       if (mb86a16_write(state, 0x32, 0x02 | (loop << 2)) < 0) {
+               dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+               return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+static int iq_vt_set(struct mb86a16_state *state, unsigned char IQINV)
+{
+       /* Viterbi Rate, IQ Settings */
+       if (mb86a16_write(state, 0x06, 0xdf | (IQINV << 5)) < 0) {
+               dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+               return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+static int FEC_srst(struct mb86a16_state *state)
+{
+       if (mb86a16_write(state, MB86A16_RESET, 0x02) < 0) {
+               dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+               return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+static int S2T_set(struct mb86a16_state *state, unsigned char S2T)
+{
+       if (mb86a16_write(state, 0x34, 0x70 | S2T) < 0) {
+               dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+               return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+static int S45T_set(struct mb86a16_state *state, unsigned char S4T, unsigned char S5T)
+{
+       if (mb86a16_write(state, 0x35, 0x00 | (S5T << 4) | S4T) < 0) {
+               dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+               return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+
+static int mb86a16_set_fe(struct mb86a16_state *state)
+{
+       u8 agcval, cnmval;
+
+       int i, j;
+       int fOSC = 0;
+       int fOSC_start = 0;
+       int wait_t;
+       int fcp;
+       int swp_ofs;
+       int V[60];
+       u8 SIG1MIN;
+
+       unsigned char CREN, AFCEN, AFCEXEN;
+       unsigned char SIG1;
+       unsigned char TIMINT1, TIMINT2, TIMEXT;
+       unsigned char S0T, S1T;
+       unsigned char S2T;
+/*     unsigned char S2T, S3T; */
+       unsigned char S4T, S5T;
+       unsigned char AFCEX_L, AFCEX_H;
+       unsigned char R;
+       unsigned char VIRM;
+       unsigned char ETH, VIA;
+       unsigned char junk;
+
+       int loop;
+       int ftemp;
+       int v, vmax, vmin;
+       int vmax_his, vmin_his;
+       int swp_freq, prev_swp_freq[20];
+       int prev_freq_num;
+       int signal_dupl;
+       int afcex_freq;
+       int signal;
+       int afcerr;
+       int temp_freq, delta_freq;
+       int dagcm[4];
+       int smrt_d;
+/*     int freq_err; */
+       int n;
+       int ret = -1;
+       int sync;
+
+       dprintk(verbose, MB86A16_INFO, 1, "freq=%d Mhz, symbrt=%d Ksps", state->frequency, state->srate);
+
+       fcp = 3000;
+       swp_ofs = state->srate / 4;
+
+       for (i = 0; i < 60; i++)
+               V[i] = -1;
+
+       for (i = 0; i < 20; i++)
+               prev_swp_freq[i] = 0;
+
+       SIG1MIN = 25;
+
+       for (n = 0; ((n < 3) && (ret == -1)); n++) {
+               SEQ_set(state, 0);
+               iq_vt_set(state, 0);
+
+               CREN = 0;
+               AFCEN = 0;
+               AFCEXEN = 1;
+               TIMINT1 = 0;
+               TIMINT2 = 1;
+               TIMEXT = 2;
+               S1T = 0;
+               S0T = 0;
+
+               if (initial_set(state) < 0) {
+                       dprintk(verbose, MB86A16_ERROR, 1, "initial set failed");
+                       return -1;
+               }
+               if (DAGC_data_set(state, 3, 2) < 0) {
+                       dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
+                       return -1;
+               }
+               if (EN_set(state, CREN, AFCEN) < 0) {
+                       dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
+                       return -1; /* (0, 0) */
+               }
+               if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
+                       dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+                       return -1; /* (1, smrt) = (1, symbolrate) */
+               }
+               if (CNTM_set(state, TIMINT1, TIMINT2, TIMEXT) < 0) {
+                       dprintk(verbose, MB86A16_ERROR, 1, "CNTM set error");
+                       return -1; /* (0, 1, 2) */
+               }
+               if (S01T_set(state, S1T, S0T) < 0) {
+                       dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
+                       return -1; /* (0, 0) */
+               }
+               smrt_info_get(state, state->srate);
+               if (smrt_set(state, state->srate) < 0) {
+                       dprintk(verbose, MB86A16_ERROR, 1, "smrt info get error");
+                       return -1;
+               }
+
+               R = vco_dev_get(state, state->srate);
+               if (R == 1)
+                       fOSC_start = state->frequency;
+
+               else if (R == 0) {
+                       if (state->frequency % 2 == 0) {
+                               fOSC_start = state->frequency;
+                       } else {
+                               fOSC_start = state->frequency + 1;
+                               if (fOSC_start > 2150)
+                                       fOSC_start = state->frequency - 1;
+                       }
+               }
+               loop = 1;
+               ftemp = fOSC_start * 1000;
+               vmax = 0 ;
+               while (loop == 1) {
+                       ftemp = ftemp + swp_ofs;
+                       vmax++;
+
+                       /* Upper bound */
+                       if (ftemp > 2150000) {
+                               loop = 0;
+                               vmax--;
+                       } else {
+                               if ((ftemp == 2150000) ||
+                                   (ftemp - state->frequency * 1000 >= fcp + state->srate / 4))
+                                       loop = 0;
+                       }
+               }
+
+               loop = 1;
+               ftemp = fOSC_start * 1000;
+               vmin = 0 ;
+               while (loop == 1) {
+                       ftemp = ftemp - swp_ofs;
+                       vmin--;
+
+                       /* Lower bound */
+                       if (ftemp < 950000) {
+                               loop = 0;
+                               vmin++;
+                       } else {
+                               if ((ftemp == 950000) ||
+                                   (state->frequency * 1000 - ftemp >= fcp + state->srate / 4))
+                                       loop = 0;
+                       }
+               }
+
+               wait_t = (8000 + state->srate / 2) / state->srate;
+               if (wait_t == 0)
+                       wait_t = 1;
+
+               i = 0;
+               j = 0;
+               prev_freq_num = 0;
+               loop = 1;
+               signal = 0;
+               vmax_his = 0;
+               vmin_his = 0;
+               v = 0;
+
+               while (loop == 1) {
+                       swp_info_get(state, fOSC_start, state->srate,
+                                    v, R, swp_ofs, &fOSC,
+                                    &afcex_freq, &AFCEX_L, &AFCEX_H);
+
+                       udelay(100);
+                       if (rf_val_set(state, fOSC, state->srate, R) < 0) {
+                               dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+                               return -1;
+                       }
+                       udelay(100);
+                       if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+                               dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+                               return -1;
+                       }
+                       if (srst(state) < 0) {
+                               dprintk(verbose, MB86A16_ERROR, 1, "srst error");
+                               return -1;
+                       }
+                       msleep_interruptible(wait_t);
+
+                       if (mb86a16_read(state, 0x37, &SIG1) != 2) {
+                               dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+                               return -1;
+                       }
+                       V[30 + v] = SIG1 ;
+                       swp_freq = swp_freq_calcuation(state, i, v, V, vmax, vmin,
+                                                     SIG1MIN, fOSC, afcex_freq,
+                                                     swp_ofs, &SIG1);  /* changed */
+
+                       signal_dupl = 0;
+                       for (j = 0; j < prev_freq_num; j++) {
+                               if ((ABS(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) {
+                                       signal_dupl = 1;
+                                       dprintk(verbose, MB86A16_INFO, 1, "Probably Duplicate Signal, j = %d", j);
+                               }
+                       }
+                       if ((signal_dupl == 0) && (swp_freq > 0) && (ABS(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) {
+                               dprintk(verbose, MB86A16_DEBUG, 1, "------ Signal detect ------ [swp_freq=[%07d, srate=%05d]]", swp_freq, state->srate);
+                               prev_swp_freq[prev_freq_num] = swp_freq;
+                               prev_freq_num++;
+                               swp_info_get2(state, state->srate, R, swp_freq,
+                                             &afcex_freq, &fOSC,
+                                             &AFCEX_L, &AFCEX_H);
+
+                               if (rf_val_set(state, fOSC, state->srate, R) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+                                       return -1;
+                               }
+                               if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+                                       return -1;
+                               }
+                               signal = signal_det(state, state->srate, &SIG1);
+                               if (signal == 1) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "***** Signal Found *****");
+                                       loop = 0;
+                               } else {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "!!!!! No signal !!!!!, try again...");
+                                       smrt_info_get(state, state->srate);
+                                       if (smrt_set(state, state->srate) < 0) {
+                                               dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+                                               return -1;
+                                       }
+                               }
+                       }
+                       if (v > vmax)
+                               vmax_his = 1 ;
+                       if (v < vmin)
+                               vmin_his = 1 ;
+                       i++;
+
+                       if ((i % 2 == 1) && (vmax_his == 1))
+                               i++;
+                       if ((i % 2 == 0) && (vmin_his == 1))
+                               i++;
+
+                       if (i % 2 == 1)
+                               v = (i + 1) / 2;
+                       else
+                               v = -i / 2;
+
+                       if ((vmax_his == 1) && (vmin_his == 1))
+                               loop = 0 ;
+               }
+
+               if (signal == 1) {
+                       dprintk(verbose, MB86A16_INFO, 1, " Start Freq Error Check");
+                       S1T = 7 ;
+                       S0T = 1 ;
+                       CREN = 0 ;
+                       AFCEN = 1 ;
+                       AFCEXEN = 0 ;
+
+                       if (S01T_set(state, S1T, S0T) < 0) {
+                               dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
+                               return -1;
+                       }
+                       smrt_info_get(state, state->srate);
+                       if (smrt_set(state, state->srate) < 0) {
+                               dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+                               return -1;
+                       }
+                       if (EN_set(state, CREN, AFCEN) < 0) {
+                               dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
+                               return -1;
+                       }
+                       if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
+                               dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+                               return -1;
+                       }
+                       afcex_info_get(state, afcex_freq, &AFCEX_L, &AFCEX_H);
+                       if (afcofs_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+                               dprintk(verbose, MB86A16_ERROR, 1, "AFCOFS data set error");
+                               return -1;
+                       }
+                       if (srst(state) < 0) {
+                               dprintk(verbose, MB86A16_ERROR, 1, "srst error");
+                               return -1;
+                       }
+                       /* delay 4~200 */
+                       wait_t = 200000 / state->master_clk + 200000 / state->srate;
+                       msleep(wait_t);
+                       afcerr = afcerr_chk(state);
+                       if (afcerr == -1)
+                               return -1;
+
+                       swp_freq = fOSC * 1000 + afcerr ;
+                       AFCEXEN = 1 ;
+                       if (state->srate >= 1500)
+                               smrt_d = state->srate / 3;
+                       else
+                               smrt_d = state->srate / 2;
+                       smrt_info_get(state, smrt_d);
+                       if (smrt_set(state, smrt_d) < 0) {
+                               dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+                               return -1;
+                       }
+                       if (AFCEXEN_set(state, AFCEXEN, smrt_d) < 0) {
+                               dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+                               return -1;
+                       }
+                       R = vco_dev_get(state, smrt_d);
+                       if (DAGC_data_set(state, 2, 0) < 0) {
+                               dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
+                               return -1;
+                       }
+                       for (i = 0; i < 3; i++) {
+                               temp_freq = swp_freq + (i - 1) * state->srate / 8;
+                               swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+                               if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+                                       return -1;
+                               }
+                               if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+                                       return -1;
+                               }
+                               wait_t = 200000 / state->master_clk + 40000 / smrt_d;
+                               msleep(wait_t);
+                               dagcm[i] = dagcm_val_get(state);
+                       }
+                       if ((dagcm[0] > dagcm[1]) &&
+                           (dagcm[0] > dagcm[2]) &&
+                           (dagcm[0] - dagcm[1] > 2 * (dagcm[2] - dagcm[1]))) {
+
+                               temp_freq = swp_freq - 2 * state->srate / 8;
+                               swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+                               if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+                                       return -1;
+                               }
+                               if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "afcex data set");
+                                       return -1;
+                               }
+                               wait_t = 200000 / state->master_clk + 40000 / smrt_d;
+                               msleep(wait_t);
+                               dagcm[3] = dagcm_val_get(state);
+                               if (dagcm[3] > dagcm[1])
+                                       delta_freq = (dagcm[2] - dagcm[0] + dagcm[1] - dagcm[3]) * state->srate / 300;
+                               else
+                                       delta_freq = 0;
+                       } else if ((dagcm[2] > dagcm[1]) &&
+                                  (dagcm[2] > dagcm[0]) &&
+                                  (dagcm[2] - dagcm[1] > 2 * (dagcm[0] - dagcm[1]))) {
+
+                               temp_freq = swp_freq + 2 * state->srate / 8;
+                               swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+                               if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "rf val set");
+                                       return -1;
+                               }
+                               if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "afcex data set");
+                                       return -1;
+                               }
+                               wait_t = 200000 / state->master_clk + 40000 / smrt_d;
+                               msleep(wait_t);
+                               dagcm[3] = dagcm_val_get(state);
+                               if (dagcm[3] > dagcm[1])
+                                       delta_freq = (dagcm[2] - dagcm[0] + dagcm[3] - dagcm[1]) * state->srate / 300;
+                               else
+                                       delta_freq = 0 ;
+
+                       } else {
+                               delta_freq = 0 ;
+                       }
+                       dprintk(verbose, MB86A16_INFO, 1, "SWEEP Frequency = %d", swp_freq);
+                       swp_freq += delta_freq;
+                       dprintk(verbose, MB86A16_INFO, 1, "Adjusting .., DELTA Freq = %d, SWEEP Freq=%d", delta_freq, swp_freq);
+                       if (ABS(state->frequency * 1000 - swp_freq) > 3800) {
+                               dprintk(verbose, MB86A16_INFO, 1, "NO  --  SIGNAL !");
+                       } else {
+
+                               S1T = 0;
+                               S0T = 3;
+                               CREN = 1;
+                               AFCEN = 0;
+                               AFCEXEN = 1;
+
+                               if (S01T_set(state, S1T, S0T) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
+                                       return -1;
+                               }
+                               if (DAGC_data_set(state, 0, 0) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
+                                       return -1;
+                               }
+                               R = vco_dev_get(state, state->srate);
+                               smrt_info_get(state, state->srate);
+                               if (smrt_set(state, state->srate) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+                                       return -1;
+                               }
+                               if (EN_set(state, CREN, AFCEN) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
+                                       return -1;
+                               }
+                               if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+                                       return -1;
+                               }
+                               swp_info_get2(state, state->srate, R, swp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+                               if (rf_val_set(state, fOSC, state->srate, R) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+                                       return -1;
+                               }
+                               if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+                                       return -1;
+                               }
+                               if (srst(state) < 0) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "srst error");
+                                       return -1;
+                               }
+                               wait_t = 7 + (10000 + state->srate / 2) / state->srate;
+                               if (wait_t == 0)
+                                       wait_t = 1;
+                               msleep_interruptible(wait_t);
+                               if (mb86a16_read(state, 0x37, &SIG1) != 2) {
+                                       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+                                       return -EREMOTEIO;
+                               }
+
+                               if (SIG1 > 110) {
+                                       S2T = 4; S4T = 1; S5T = 6; ETH = 4; VIA = 6;
+                                       wait_t = 7 + (917504 + state->srate / 2) / state->srate;
+                               } else if (SIG1 > 105) {
+                                       S2T = 4; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+                                       wait_t = 7 + (1048576 + state->srate / 2) / state->srate;
+                               } else if (SIG1 > 85) {
+                                       S2T = 5; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+                                       wait_t = 7 + (1310720 + state->srate / 2) / state->srate;
+                               } else if (SIG1 > 65) {
+                                       S2T = 6; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+                                       wait_t = 7 + (1572864 + state->srate / 2) / state->srate;
+                               } else {
+                                       S2T = 7; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+                                       wait_t = 7 + (2097152 + state->srate / 2) / state->srate;
+                               }
+                               wait_t *= 2; /* FOS */
+                               S2T_set(state, S2T);
+                               S45T_set(state, S4T, S5T);
+                               Vi_set(state, ETH, VIA);
+                               srst(state);
+                               msleep_interruptible(wait_t);
+                               sync = sync_chk(state, &VIRM);
+                               dprintk(verbose, MB86A16_INFO, 1, "-------- Viterbi=[%d] SYNC=[%d] ---------", VIRM, sync);
+                               if (VIRM) {
+                                       if (VIRM == 4) {
+                                               /* 5/6 */
+                                               if (SIG1 > 110)
+                                                       wait_t = (786432 + state->srate / 2) / state->srate;
+                                               else
+                                                       wait_t = (1572864 + state->srate / 2) / state->srate;
+                                               if (state->srate < 5000)
+                                                       /* FIXME ! , should be a long wait ! */
+                                                       msleep_interruptible(wait_t);
+                                               else
+                                                       msleep_interruptible(wait_t);
+
+                                               if (sync_chk(state, &junk) == 0) {
+                                                       iq_vt_set(state, 1);
+                                                       FEC_srst(state);
+                                               }
+                                       }
+                                       /* 1/2, 2/3, 3/4, 7/8 */
+                                       if (SIG1 > 110)
+                                               wait_t = (786432 + state->srate / 2) / state->srate;
+                                       else
+                                               wait_t = (1572864 + state->srate / 2) / state->srate;
+                                       msleep_interruptible(wait_t);
+                                       SEQ_set(state, 1);
+                               } else {
+                                       dprintk(verbose, MB86A16_INFO, 1, "NO  -- SYNC");
+                                       SEQ_set(state, 1);
+                                       ret = -1;
+                               }
+                       }
+               } else {
+                       dprintk(verbose, MB86A16_INFO, 1, "NO  -- SIGNAL");
+                       ret = -1;
+               }
+
+               sync = sync_chk(state, &junk);
+               if (sync) {
+                       dprintk(verbose, MB86A16_INFO, 1, "******* SYNC *******");
+                       freqerr_chk(state, state->frequency, state->srate, 1);
+                       ret = 0;
+                       break;
+               }
+       }
+
+       mb86a16_read(state, 0x15, &agcval);
+       mb86a16_read(state, 0x26, &cnmval);
+       dprintk(verbose, MB86A16_INFO, 1, "AGC = %02x CNM = %02x", agcval, cnmval);
+
+       return ret;
+}
+
+static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe,
+                                  struct dvb_diseqc_master_cmd *cmd)
+{
+       struct mb86a16_state *state = fe->demodulator_priv;
+       int i;
+       u8 regs;
+
+       if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0)
+               goto err;
+       if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0)
+               goto err;
+       if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0)
+               goto err;
+
+       regs = 0x18;
+
+       if (cmd->msg_len > 5 || cmd->msg_len < 4)
+               return -EINVAL;
+
+       for (i = 0; i < cmd->msg_len; i++) {
+               if (mb86a16_write(state, regs, cmd->msg[i]) < 0)
+                       goto err;
+
+               regs++;
+       }
+       i += 0x90;
+
+       msleep_interruptible(10);
+
+       if (mb86a16_write(state, MB86A16_DCC1, i) < 0)
+               goto err;
+       if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+               goto err;
+
+       return 0;
+
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static int mb86a16_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
+{
+       struct mb86a16_state *state = fe->demodulator_priv;
+
+       switch (burst) {
+       case SEC_MINI_A:
+               if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
+                                                      MB86A16_DCC1_TBEN  |
+                                                      MB86A16_DCC1_TBO) < 0)
+                       goto err;
+               if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+                       goto err;
+               break;
+       case SEC_MINI_B:
+               if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
+                                                      MB86A16_DCC1_TBEN) < 0)
+                       goto err;
+               if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+                       goto err;
+               break;
+       }
+
+       return 0;
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static int mb86a16_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+       struct mb86a16_state *state = fe->demodulator_priv;
+
+       switch (tone) {
+       case SEC_TONE_ON:
+               if (mb86a16_write(state, MB86A16_TONEOUT2, 0x00) < 0)
+                       goto err;
+               if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
+                                                      MB86A16_DCC1_CTOE) < 0)
+
+                       goto err;
+               if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+                       goto err;
+               break;
+       case SEC_TONE_OFF:
+               if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0)
+                       goto err;
+               if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0)
+                       goto err;
+               if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0)
+                       goto err;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe,
+                                       struct dvb_frontend_parameters *p)
+{
+       struct mb86a16_state *state = fe->demodulator_priv;
+
+       state->frequency = p->frequency / 1000;
+       state->srate = p->u.qpsk.symbol_rate / 1000;
+
+       if (!mb86a16_set_fe(state)) {
+               dprintk(verbose, MB86A16_ERROR, 1, "Succesfully acquired LOCK");
+               return DVBFE_ALGO_SEARCH_SUCCESS;
+       }
+
+       dprintk(verbose, MB86A16_ERROR, 1, "Lock acquisition failed!");
+       return DVBFE_ALGO_SEARCH_FAILED;
+}
+
+static void mb86a16_release(struct dvb_frontend *fe)
+{
+       struct mb86a16_state *state = fe->demodulator_priv;
+       kfree(state);
+}
+
+static int mb86a16_init(struct dvb_frontend *fe)
+{
+       return 0;
+}
+
+static int mb86a16_sleep(struct dvb_frontend *fe)
+{
+       return 0;
+}
+
+static int mb86a16_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       u8 ber_mon, ber_tab, ber_lsb, ber_mid, ber_msb, ber_tim, ber_rst;
+       u32 timer;
+
+       struct mb86a16_state *state = fe->demodulator_priv;
+
+       *ber = 0;
+       if (mb86a16_read(state, MB86A16_BERMON, &ber_mon) != 2)
+               goto err;
+       if (mb86a16_read(state, MB86A16_BERTAB, &ber_tab) != 2)
+               goto err;
+       if (mb86a16_read(state, MB86A16_BERLSB, &ber_lsb) != 2)
+               goto err;
+       if (mb86a16_read(state, MB86A16_BERMID, &ber_mid) != 2)
+               goto err;
+       if (mb86a16_read(state, MB86A16_BERMSB, &ber_msb) != 2)
+               goto err;
+       /* BER monitor invalid when BER_EN = 0  */
+       if (ber_mon & 0x04) {
+               /* coarse, fast calculation     */
+               *ber = ber_tab & 0x1f;
+               dprintk(verbose, MB86A16_DEBUG, 1, "BER coarse=[0x%02x]", *ber);
+               if (ber_mon & 0x01) {
+                       /*
+                        * BER_SEL = 1, The monitored BER is the estimated
+                        * value with a Reed-Solomon decoder error amount at
+                        * the deinterleaver output.
+                        * monitored BER is expressed as a 20 bit output in total
+                        */
+                       ber_rst = ber_mon >> 3;
+                       *ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb;
+                       if (ber_rst == 0)
+                               timer =  12500000;
+                       if (ber_rst == 1)
+                               timer =  25000000;
+                       if (ber_rst == 2)
+                               timer =  50000000;
+                       if (ber_rst == 3)
+                               timer = 100000000;
+
+                       *ber /= timer;
+                       dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber);
+               } else {
+                       /*
+                        * BER_SEL = 0, The monitored BER is the estimated
+                        * value with a Viterbi decoder error amount at the
+                        * QPSK demodulator output.
+                        * monitored BER is expressed as a 24 bit output in total
+                        */
+                       ber_tim = ber_mon >> 1;
+                       *ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb;
+                       if (ber_tim == 0)
+                               timer = 16;
+                       if (ber_tim == 1)
+                               timer = 24;
+
+                       *ber /= 2 ^ timer;
+                       dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber);
+               }
+       }
+       return 0;
+err:
+       dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+       return -EREMOTEIO;
+}
+
+static int mb86a16_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       u8 agcm = 0;
+       struct mb86a16_state *state = fe->demodulator_priv;
+
+       *strength = 0;
+       if (mb86a16_read(state, MB86A16_AGCM, &agcm) != 2) {
+               dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+               return -EREMOTEIO;
+       }
+
+       *strength = ((0xff - agcm) * 100) / 256;
+       dprintk(verbose, MB86A16_DEBUG, 1, "Signal strength=[%d %%]", (u8) *strength);
+       *strength = (0xffff - 0xff) + agcm;
+
+       return 0;
+}
+
+struct cnr {
+       u8 cn_reg;
+       u8 cn_val;
+};
+
+static const struct cnr cnr_tab[] = {
+       {  35,  2 },
+       {  40,  3 },
+       {  50,  4 },
+       {  60,  5 },
+       {  70,  6 },
+       {  80,  7 },
+       {  92,  8 },
+       { 103,  9 },
+       { 115, 10 },
+       { 138, 12 },
+       { 162, 15 },
+       { 180, 18 },
+       { 185, 19 },
+       { 189, 20 },
+       { 195, 22 },
+       { 199, 24 },
+       { 201, 25 },
+       { 202, 26 },
+       { 203, 27 },
+       { 205, 28 },
+       { 208, 30 }
+};
+
+static int mb86a16_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct mb86a16_state *state = fe->demodulator_priv;
+       int i = 0;
+       int low_tide = 2, high_tide = 30, q_level;
+       u8  cn;
+
+       *snr = 0;
+       if (mb86a16_read(state, 0x26, &cn) != 2) {
+               dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+               return -EREMOTEIO;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(cnr_tab); i++) {
+               if (cn < cnr_tab[i].cn_reg) {
+                       *snr = cnr_tab[i].cn_val;
+                       break;
+               }
+       }
+       q_level = (*snr * 100) / (high_tide - low_tide);
+       dprintk(verbose, MB86A16_ERROR, 1, "SNR (Quality) = [%d dB], Level=%d %%", *snr, q_level);
+       *snr = (0xffff - 0xff) + *snr;
+
+       return 0;
+}
+
+static int mb86a16_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       u8 dist;
+       struct mb86a16_state *state = fe->demodulator_priv;
+
+       if (mb86a16_read(state, MB86A16_DISTMON, &dist) != 2) {
+               dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+               return -EREMOTEIO;
+       }
+       *ucblocks = dist;
+
+       return 0;
+}
+
+static enum dvbfe_algo mb86a16_frontend_algo(struct dvb_frontend *fe)
+{
+       return DVBFE_ALGO_CUSTOM;
+}
+
+static struct dvb_frontend_ops mb86a16_ops = {
+       .info = {
+               .name                   = "Fujitsu MB86A16 DVB-S",
+               .type                   = FE_QPSK,
+               .frequency_min          = 950000,
+               .frequency_max          = 2150000,
+               .frequency_stepsize     = 3000,
+               .frequency_tolerance    = 0,
+               .symbol_rate_min        = 1000000,
+               .symbol_rate_max        = 45000000,
+               .symbol_rate_tolerance  = 500,
+               .caps                   = 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_QPSK    |
+                                         FE_CAN_FEC_AUTO
+       },
+       .release                        = mb86a16_release,
+
+       .get_frontend_algo              = mb86a16_frontend_algo,
+       .search                         = mb86a16_search,
+       .read_status                    = mb86a16_read_status,
+       .init                           = mb86a16_init,
+       .sleep                          = mb86a16_sleep,
+       .read_status                    = mb86a16_read_status,
+
+       .read_ber                       = mb86a16_read_ber,
+       .read_signal_strength           = mb86a16_read_signal_strength,
+       .read_snr                       = mb86a16_read_snr,
+       .read_ucblocks                  = mb86a16_read_ucblocks,
+
+       .diseqc_send_master_cmd         = mb86a16_send_diseqc_msg,
+       .diseqc_send_burst              = mb86a16_send_diseqc_burst,
+       .set_tone                       = mb86a16_set_tone,
+};
+
+struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
+                                   struct i2c_adapter *i2c_adap)
+{
+       u8 dev_id = 0;
+       struct mb86a16_state *state = NULL;
+
+       state = kmalloc(sizeof(struct mb86a16_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       state->config = config;
+       state->i2c_adap = i2c_adap;
+
+       mb86a16_read(state, 0x7f, &dev_id);
+       if (dev_id != 0xfe)
+               goto error;
+
+       memcpy(&state->frontend.ops, &mb86a16_ops, sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+       state->frontend.ops.set_voltage = state->config->set_voltage;
+
+       return &state->frontend;
+error:
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(mb86a16_attach);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Manu Abraham");
diff --git a/drivers/media/dvb/frontends/mb86a16.h b/drivers/media/dvb/frontends/mb86a16.h
new file mode 100644 (file)
index 0000000..6ea8c37
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+       Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MB86A16_H
+#define __MB86A16_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+
+struct mb86a16_config {
+       u8 demod_address;
+
+       int (*set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+};
+
+
+
+#if defined(CONFIG_DVB_MB86A16) || (defined(CONFIG_DVB_MB86A16_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
+                                          struct i2c_adapter *i2c_adap);
+
+#else
+
+static inline struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
+                                          struct i2c_adapter *i2c_adap)
+{
+       printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+#endif /* CONFIG_DVB_MB86A16 */
+
+#endif /* __MB86A16_H */
diff --git a/drivers/media/dvb/frontends/mb86a16_priv.h b/drivers/media/dvb/frontends/mb86a16_priv.h
new file mode 100644 (file)
index 0000000..360a35a
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+       Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MB86A16_PRIV_H
+#define __MB86A16_PRIV_H
+
+#define MB86A16_TSOUT          0x00
+#define MB86A16_TSOUT_HIZSEL   (0x01 << 5)
+#define MB86A16_TSOUT_HIZCNTI  (0x01 << 4)
+#define MB86A16_TSOUT_MODE     (0x01 << 3)
+#define MB86A16_TSOUT_ORDER    (0x01 << 2)
+#define MB86A16_TSOUT_ERROR    (0x01 << 1)
+#define Mb86A16_TSOUT_EDGE     (0x01 << 0)
+
+#define MB86A16_FEC            0x01
+#define MB86A16_FEC_FSYNC      (0x01 << 5)
+#define MB86A16_FEC_PCKB8      (0x01 << 4)
+#define MB86A16_FEC_DVDS       (0x01 << 3)
+#define MB86A16_FEC_EREN       (0x01 << 2)
+#define Mb86A16_FEC_RSEN       (0x01 << 1)
+#define MB86A16_FEC_DIEN       (0x01 << 0)
+
+#define MB86A16_AGC            0x02
+#define MB86A16_AGC_AGMD       (0x01 << 6)
+#define MB86A16_AGC_AGCW       (0x0f << 2)
+#define MB86A16_AGC_AGCP       (0x01 << 1)
+#define MB86A16_AGC_AGCR       (0x01 << 0)
+
+#define MB86A16_SRATE1         0x03
+#define MB86A16_SRATE1_DECI    (0x07 << 2)
+#define MB86A16_SRATE1_CSEL    (0x01 << 1)
+#define MB86A16_SRATE1_RSEL    (0x01 << 0)
+
+#define MB86A16_SRATE2         0x04
+#define MB86A16_SRATE2_STOFSL  (0xff << 0)
+
+#define MB86A16_SRATE3         0x05
+#define MB86A16_SRATE2_STOFSH  (0xff << 0)
+
+#define MB86A16_VITERBI                0x06
+#define MB86A16_FRAMESYNC      0x07
+#define MB86A16_CRLFILTCOEF1   0x08
+#define MB86A16_CRLFILTCOEF2   0x09
+#define MB86A16_STRFILTCOEF1   0x0a
+#define MB86A16_STRFILTCOEF2   0x0b
+#define MB86A16_RESET          0x0c
+#define MB86A16_STATUS         0x0d
+#define MB86A16_AFCML          0x0e
+#define MB86A16_AFCMH          0x0f
+#define MB86A16_BERMON         0x10
+#define MB86A16_BERTAB         0x11
+#define MB86A16_BERLSB         0x12
+#define MB86A16_BERMID         0x13
+#define MB86A16_BERMSB         0x14
+#define MB86A16_AGCM           0x15
+
+#define MB86A16_DCC1           0x16
+#define MB86A16_DCC1_DISTA     (0x01 << 7)
+#define MB86A16_DCC1_PRTY      (0x01 << 6)
+#define MB86A16_DCC1_CTOE      (0x01 << 5)
+#define MB86A16_DCC1_TBEN      (0x01 << 4)
+#define MB86A16_DCC1_TBO       (0x01 << 3)
+#define MB86A16_DCC1_NUM       (0x07 << 0)
+
+#define MB86A16_DCC2           0x17
+#define MB86A16_DCC2_DCBST     (0x01 << 0)
+
+#define MB86A16_DCC3           0x18
+#define MB86A16_DCC3_CODE0     (0xff << 0)
+
+#define MB86A16_DCC4           0x19
+#define MB86A16_DCC4_CODE1     (0xff << 0)
+
+#define MB86A16_DCC5           0x1a
+#define MB86A16_DCC5_CODE2     (0xff << 0)
+
+#define MB86A16_DCC6           0x1b
+#define MB86A16_DCC6_CODE3     (0xff << 0)
+
+#define MB86A16_DCC7           0x1c
+#define MB86A16_DCC7_CODE4     (0xff << 0)
+
+#define MB86A16_DCC8           0x1d
+#define MB86A16_DCC8_CODE5     (0xff << 0)
+
+#define MB86A16_DCCOUT         0x1e
+#define MB86A16_DCCOUT_DISEN   (0x01 << 0)
+
+#define MB86A16_TONEOUT1       0x1f
+#define MB86A16_TONE_TDIVL     (0xff << 0)
+
+#define MB86A16_TONEOUT2       0x20
+#define MB86A16_TONE_TMD       (0x03 << 2)
+#define MB86A16_TONE_TDIVH     (0x03 << 0)
+
+#define MB86A16_FREQ1          0x21
+#define MB86A16_FREQ2          0x22
+#define MB86A16_FREQ3          0x23
+#define MB86A16_FREQ4          0x24
+#define MB86A16_FREQSET                0x25
+#define MB86A16_CNM            0x26
+#define MB86A16_PORT0          0x27
+#define MB86A16_PORT1          0x28
+#define MB86A16_DRCFILT                0x29
+#define MB86A16_AFC            0x2a
+#define MB86A16_AFCEXL         0x2b
+#define MB86A16_AFCEXH         0x2c
+#define MB86A16_DAGC           0x2d
+#define MB86A16_SEQMODE                0x32
+#define MB86A16_S0S1T          0x33
+#define MB86A16_S2S3T          0x34
+#define MB86A16_S4S5T          0x35
+#define MB86A16_CNTMR          0x36
+#define MB86A16_SIG1           0x37
+#define MB86A16_SIG2           0x38
+#define MB86A16_VIMAG          0x39
+#define MB86A16_VISET1         0x3a
+#define MB86A16_VISET2         0x3b
+#define MB86A16_VISET3         0x3c
+#define MB86A16_FAGCS1         0x3d
+#define MB86A16_FAGCS2         0x3e
+#define MB86A16_FAGCS3         0x3f
+#define MB86A16_FAGCS4         0x40
+#define MB86A16_FAGCS5         0x41
+#define MB86A16_FAGCS6         0x42
+#define MB86A16_CRM            0x43
+#define MB86A16_STRM           0x44
+#define MB86A16_DAGCML         0x45
+#define MB86A16_DAGCMH         0x46
+#define MB86A16_QPSKTST                0x49
+#define MB86A16_DISTMON                0x52
+#define MB86A16_VERSION                0x7f
+
+#endif /* __MB86A16_PRIV_H */
index 6c1dbf9288d8b34d652bdf4b3465f3d46d0d4b1e..6ca533ea0f0ec047258a568335b7fa17e3762b96 100644 (file)
@@ -426,6 +426,10 @@ struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
        id = tda10021_readreg(state, 0x1a);
        if ((id & 0xf0) != 0x70) goto error;
 
+       /* Don't claim TDA10023 */
+       if (id == 0x7d)
+               goto error;
+
        printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n",
               state->config->demod_address, id);
 
diff --git a/drivers/media/dvb/frontends/tda665x.c b/drivers/media/dvb/frontends/tda665x.c
new file mode 100644 (file)
index 0000000..87d5273
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+       TDA665x tuner driver
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "dvb_frontend.h"
+#include "tda665x.h"
+
+struct tda665x_state {
+       struct dvb_frontend             *fe;
+       struct i2c_adapter              *i2c;
+       const struct tda665x_config     *config;
+
+       u32 frequency;
+       u32 bandwidth;
+};
+
+static int tda665x_read(struct tda665x_state *state, u8 *buf)
+{
+       const struct tda665x_config *config = state->config;
+       int err = 0;
+       struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD, .buf = buf, .len = 2 };
+
+       err = i2c_transfer(state->i2c, &msg, 1);
+       if (err != 1)
+               goto exit;
+
+       return err;
+exit:
+       printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
+       return err;
+}
+
+static int tda665x_write(struct tda665x_state *state, u8 *buf, u8 length)
+{
+       const struct tda665x_config *config = state->config;
+       int err = 0;
+       struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = length };
+
+       err = i2c_transfer(state->i2c, &msg, 1);
+       if (err != 1)
+               goto exit;
+
+       return err;
+exit:
+       printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
+       return err;
+}
+
+static int tda665x_get_state(struct dvb_frontend *fe,
+                            enum tuner_param param,
+                            struct tuner_state *tstate)
+{
+       struct tda665x_state *state = fe->tuner_priv;
+       int err = 0;
+
+       switch (param) {
+       case DVBFE_TUNER_FREQUENCY:
+               tstate->frequency = state->frequency;
+               break;
+       case DVBFE_TUNER_BANDWIDTH:
+               break;
+       default:
+               printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
+               err = -EINVAL;
+               break;
+       }
+
+       return err;
+}
+
+static int tda665x_get_status(struct dvb_frontend *fe, u32 *status)
+{
+       struct tda665x_state *state = fe->tuner_priv;
+       u8 result = 0;
+       int err = 0;
+
+       *status = 0;
+
+       err = tda665x_read(state, &result);
+       if (err < 0)
+               goto exit;
+
+       if ((result >> 6) & 0x01) {
+               printk(KERN_DEBUG "%s: Tuner Phase Locked\n", __func__);
+               *status = 1;
+       }
+
+       return err;
+exit:
+       printk(KERN_ERR "%s: I/O Error\n", __func__);
+       return err;
+}
+
+static int tda665x_set_state(struct dvb_frontend *fe,
+                            enum tuner_param param,
+                            struct tuner_state *tstate)
+{
+       struct tda665x_state *state = fe->tuner_priv;
+       const struct tda665x_config *config = state->config;
+       u32 frequency, status = 0;
+       u8 buf[4];
+       int err = 0;
+
+       if (param & DVBFE_TUNER_FREQUENCY) {
+
+               frequency = tstate->frequency;
+               if ((frequency < config->frequency_max) || (frequency > config->frequency_min)) {
+                       printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n", __func__, frequency);
+                       return -EINVAL;
+               }
+
+               frequency += config->frequency_offst;
+               frequency *= config->ref_multiplier;
+               frequency += config->ref_divider >> 1;
+               frequency /= config->ref_divider;
+
+               buf[0] = (u8) (frequency & 0x7f00) >> 8;
+               buf[1] = (u8) (frequency & 0x00ff) >> 0;
+               buf[2] = 0x80 | 0x40 | 0x02;
+               buf[3] = 0x00;
+
+               /* restore frequency */
+               frequency = tstate->frequency;
+
+               if (frequency < 153000000) {
+                       /* VHF-L */
+                       buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */
+                       if (frequency < 68000000)
+                               buf[3] |= 0x40; /* 83uA */
+                       if (frequency < 1040000000)
+                               buf[3] |= 0x60; /* 122uA */
+                       if (frequency < 1250000000)
+                               buf[3] |= 0x80; /* 163uA */
+                       else
+                               buf[3] |= 0xa0; /* 254uA */
+               } else if (frequency < 438000000) {
+                       /* VHF-H */
+                       buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */
+                       if (frequency < 230000000)
+                               buf[3] |= 0x40;
+                       if (frequency < 300000000)
+                               buf[3] |= 0x60;
+                       else
+                               buf[3] |= 0x80;
+               } else {
+                       /* UHF */
+                       buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */
+                       if (frequency < 470000000)
+                               buf[3] |= 0x60;
+                       if (frequency < 526000000)
+                               buf[3] |= 0x80;
+                       else
+                               buf[3] |= 0xa0;
+               }
+
+               /* Set params */
+               err = tda665x_write(state, buf, 5);
+               if (err < 0)
+                       goto exit;
+
+               /* sleep for some time */
+               printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__);
+               msleep(20);
+               /* check status */
+               err = tda665x_get_status(fe, &status);
+               if (err < 0)
+                       goto exit;
+
+               if (status == 1) {
+                       printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n", __func__, status);
+                       state->frequency = frequency; /* cache successful state */
+               } else {
+                       printk(KERN_ERR "%s: No Phase lock: status=%d\n", __func__, status);
+               }
+       } else {
+               printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
+               return -EINVAL;
+       }
+
+       return 0;
+exit:
+       printk(KERN_ERR "%s: I/O Error\n", __func__);
+       return err;
+}
+
+static int tda665x_release(struct dvb_frontend *fe)
+{
+       struct tda665x_state *state = fe->tuner_priv;
+
+       fe->tuner_priv = NULL;
+       kfree(state);
+       return 0;
+}
+
+static struct dvb_tuner_ops tda665x_ops = {
+
+       .set_state      = tda665x_set_state,
+       .get_state      = tda665x_get_state,
+       .get_status     = tda665x_get_status,
+       .release        = tda665x_release
+};
+
+struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
+                                   const struct tda665x_config *config,
+                                   struct i2c_adapter *i2c)
+{
+       struct tda665x_state *state = NULL;
+       struct dvb_tuner_info *info;
+
+       state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL);
+       if (state == NULL)
+               goto exit;
+
+       state->config           = config;
+       state->i2c              = i2c;
+       state->fe               = fe;
+       fe->tuner_priv          = state;
+       fe->ops.tuner_ops       = tda665x_ops;
+       info                     = &fe->ops.tuner_ops.info;
+
+       memcpy(info->name, config->name, sizeof(config->name));
+       info->frequency_min     = config->frequency_min;
+       info->frequency_max     = config->frequency_max;
+       info->frequency_step    = config->frequency_offst;
+
+       printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name);
+
+       return fe;
+
+exit:
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(tda665x_attach);
+
+MODULE_DESCRIPTION("TDA665x driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda665x.h b/drivers/media/dvb/frontends/tda665x.h
new file mode 100644 (file)
index 0000000..ec7927a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+       TDA665x tuner driver
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TDA665x_H
+#define __TDA665x_H
+
+struct tda665x_config {
+       char name[128];
+
+       u8      addr;
+       u32     frequency_min;
+       u32     frequency_max;
+       u32     frequency_offst;
+       u32     ref_multiplier;
+       u32     ref_divider;
+};
+
+#if defined(CONFIG_DVB_TDA665x) || (defined(CONFIG_DVB_TDA665x_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
+                                          const struct tda665x_config *config,
+                                          struct i2c_adapter *i2c);
+
+#else
+
+static inline struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
+                                                 const struct tda665x_config *config,
+                                                 struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+#endif /* CONFIG_DVB_TDA665x */
+
+#endif /* __TDA665x_H */
diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig
new file mode 100644 (file)
index 0000000..f7b72a3
--- /dev/null
@@ -0,0 +1,32 @@
+config MANTIS_CORE
+       tristate "Mantis/Hopper PCI bridge based devices"
+       depends on PCI && I2C && INPUT
+
+       help
+         Support for PCI cards based on the Mantis and Hopper PCi bridge.
+
+         Say Y if you own such a device and want to use it.
+
+config DVB_MANTIS
+       tristate "MANTIS based cards"
+       depends on MANTIS_CORE && DVB_CORE && PCI && I2C
+       select DVB_MB86A16
+       select DVB_ZL10353
+       select DVB_STV0299
+       select DVB_PLL
+       help
+         Support for PCI cards based on the Mantis PCI bridge.
+         Say Y when you have a Mantis based DVB card and want to use it.
+
+         If unsure say N.
+
+config DVB_HOPPER
+       tristate "HOPPER based cards"
+       depends on MANTIS_CORE && DVB_CORE && PCI && I2C
+       select DVB_ZL10353
+       select DVB_PLL
+       help
+         Support for PCI cards based on the Hopper  PCI bridge.
+         Say Y when you have a Hopper based DVB card and want to use it.
+
+         If unsure say N
diff --git a/drivers/media/dvb/mantis/Makefile b/drivers/media/dvb/mantis/Makefile
new file mode 100644 (file)
index 0000000..98dc5cd
--- /dev/null
@@ -0,0 +1,28 @@
+mantis_core-objs :=    mantis_ioc.o    \
+                       mantis_uart.o   \
+                       mantis_dma.o    \
+                       mantis_pci.o    \
+                       mantis_i2c.o    \
+                       mantis_dvb.o    \
+                       mantis_evm.o    \
+                       mantis_hif.o    \
+                       mantis_ca.o     \
+                       mantis_pcmcia.o \
+                       mantis_input.o
+
+mantis-objs    :=      mantis_cards.o  \
+                       mantis_vp1033.o \
+                       mantis_vp1034.o \
+                       mantis_vp1041.o \
+                       mantis_vp2033.o \
+                       mantis_vp2040.o \
+                       mantis_vp3030.o
+
+hopper-objs    :=      hopper_cards.o  \
+                       hopper_vp3028.o
+
+obj-$(CONFIG_MANTIS_CORE)      += mantis_core.o
+obj-$(CONFIG_DVB_MANTIS)       += mantis.o
+obj-$(CONFIG_DVB_HOPPER)       += hopper.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/dvb/mantis/hopper_cards.c
new file mode 100644 (file)
index 0000000..d073c61
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+       Hopper PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/irq.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "hopper_vp3028.h"
+#include "mantis_dma.h"
+#include "mantis_dvb.h"
+#include "mantis_uart.h"
+#include "mantis_ioc.h"
+#include "mantis_pci.h"
+#include "mantis_i2c.h"
+#include "mantis_reg.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+
+#define DRIVER_NAME    "Hopper"
+
+static char *label[10] = {
+       "DMA",
+       "IRQ-0",
+       "IRQ-1",
+       "OCERR",
+       "PABRT",
+       "RIPRR",
+       "PPERR",
+       "FTRGT",
+       "RISCI",
+       "RACK"
+};
+
+static int devs;
+
+static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
+{
+       u32 stat = 0, mask = 0, lstat = 0, mstat = 0;
+       u32 rst_stat = 0, rst_mask = 0;
+
+       struct mantis_pci *mantis;
+       struct mantis_ca *ca;
+
+       mantis = (struct mantis_pci *) dev_id;
+       if (unlikely(mantis == NULL)) {
+               dprintk(MANTIS_ERROR, 1, "Mantis == NULL");
+               return IRQ_NONE;
+       }
+       ca = mantis->mantis_ca;
+
+       stat = mmread(MANTIS_INT_STAT);
+       mask = mmread(MANTIS_INT_MASK);
+       mstat = lstat = stat & ~MANTIS_INT_RISCSTAT;
+       if (!(stat & mask))
+               return IRQ_NONE;
+
+       rst_mask  = MANTIS_GPIF_WRACK  |
+                   MANTIS_GPIF_OTHERR |
+                   MANTIS_SBUF_WSTO   |
+                   MANTIS_GPIF_EXTIRQ;
+
+       rst_stat  = mmread(MANTIS_GPIF_STATUS);
+       rst_stat &= rst_mask;
+       mmwrite(rst_stat, MANTIS_GPIF_STATUS);
+
+       mantis->mantis_int_stat = stat;
+       mantis->mantis_int_mask = mask;
+       dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask);
+       if (stat & MANTIS_INT_RISCEN) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]);
+       }
+       if (stat & MANTIS_INT_IRQ0) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]);
+               mantis->gpif_status = rst_stat;
+               wake_up(&ca->hif_write_wq);
+               schedule_work(&ca->hif_evm_work);
+       }
+       if (stat & MANTIS_INT_IRQ1) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]);
+               schedule_work(&mantis->uart_work);
+       }
+       if (stat & MANTIS_INT_OCERR) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]);
+       }
+       if (stat & MANTIS_INT_PABORT) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]);
+       }
+       if (stat & MANTIS_INT_RIPERR) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]);
+       }
+       if (stat & MANTIS_INT_PPERR) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]);
+       }
+       if (stat & MANTIS_INT_FTRGT) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]);
+       }
+       if (stat & MANTIS_INT_RISCI) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
+               mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
+               tasklet_schedule(&mantis->tasklet);
+       }
+       if (stat & MANTIS_INT_I2CDONE) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
+               wake_up(&mantis->i2c_wq);
+       }
+       mmwrite(stat, MANTIS_INT_STAT);
+       stat &= ~(MANTIS_INT_RISCEN   | MANTIS_INT_I2CDONE |
+                 MANTIS_INT_I2CRACK  | MANTIS_INT_PCMCIA7 |
+                 MANTIS_INT_PCMCIA6  | MANTIS_INT_PCMCIA5 |
+                 MANTIS_INT_PCMCIA4  | MANTIS_INT_PCMCIA3 |
+                 MANTIS_INT_PCMCIA2  | MANTIS_INT_PCMCIA1 |
+                 MANTIS_INT_PCMCIA0  | MANTIS_INT_IRQ1    |
+                 MANTIS_INT_IRQ0     | MANTIS_INT_OCERR   |
+                 MANTIS_INT_PABORT   | MANTIS_INT_RIPERR  |
+                 MANTIS_INT_PPERR    | MANTIS_INT_FTRGT   |
+                 MANTIS_INT_RISCI);
+
+       if (stat)
+               dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask);
+
+       dprintk(MANTIS_DEBUG, 0, "\n");
+       return IRQ_HANDLED;
+}
+
+static int __devinit hopper_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+       struct mantis_pci *mantis;
+       struct mantis_hwconfig *config;
+       int err = 0;
+
+       mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL);
+       if (mantis == NULL) {
+               printk(KERN_ERR "%s ERROR: Out of memory\n", __func__);
+               err = -ENOMEM;
+               goto fail0;
+       }
+
+       mantis->num             = devs;
+       mantis->verbose         = verbose;
+       mantis->pdev            = pdev;
+       config                  = (struct mantis_hwconfig *) pci_id->driver_data;
+       config->irq_handler     = &hopper_irq_handler;
+       mantis->hwconfig        = config;
+
+       err = mantis_pci_init(mantis);
+       if (err) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err);
+               goto fail1;
+       }
+
+       err = mantis_stream_control(mantis, STREAM_TO_HIF);
+       if (err < 0) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err);
+               goto fail1;
+       }
+
+       err = mantis_i2c_init(mantis);
+       if (err < 0) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err);
+               goto fail2;
+       }
+
+       err = mantis_get_mac(mantis);
+       if (err < 0) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err);
+               goto fail2;
+       }
+
+       err = mantis_dma_init(mantis);
+       if (err < 0) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err);
+               goto fail3;
+       }
+
+       err = mantis_dvb_init(mantis);
+       if (err < 0) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err);
+               goto fail4;
+       }
+       devs++;
+
+       return err;
+
+fail4:
+       dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err);
+       mantis_dma_exit(mantis);
+
+fail3:
+       dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err);
+       mantis_i2c_exit(mantis);
+
+fail2:
+       dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err);
+       mantis_pci_exit(mantis);
+
+fail1:
+       dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err);
+       kfree(mantis);
+
+fail0:
+       return err;
+}
+
+static void __devexit hopper_pci_remove(struct pci_dev *pdev)
+{
+       struct mantis_pci *mantis = pci_get_drvdata(pdev);
+
+       if (mantis) {
+               mantis_dvb_exit(mantis);
+               mantis_dma_exit(mantis);
+               mantis_i2c_exit(mantis);
+               mantis_pci_exit(mantis);
+               kfree(mantis);
+       }
+       return;
+
+}
+
+static struct pci_device_id hopper_pci_table[] = {
+       MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config),
+       { }
+};
+
+static struct pci_driver hopper_pci_driver = {
+       .name           = DRIVER_NAME,
+       .id_table       = hopper_pci_table,
+       .probe          = hopper_pci_probe,
+       .remove         = hopper_pci_remove,
+};
+
+static int __devinit hopper_init(void)
+{
+       return pci_register_driver(&hopper_pci_driver);
+}
+
+static void __devexit hopper_exit(void)
+{
+       return pci_unregister_driver(&hopper_pci_driver);
+}
+
+module_init(hopper_init);
+module_exit(hopper_exit);
+
+MODULE_DESCRIPTION("HOPPER driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/hopper_vp3028.c b/drivers/media/dvb/mantis/hopper_vp3028.c
new file mode 100644 (file)
index 0000000..96674c7
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+       Hopper VP-3028 driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "zl10353.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "hopper_vp3028.h"
+
+struct zl10353_config hopper_vp3028_config = {
+       .demod_address  = 0x0f,
+};
+
+#define MANTIS_MODEL_NAME      "VP-3028"
+#define MANTIS_DEV_TYPE                "DVB-T"
+
+static int vp3028_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+       struct i2c_adapter *adapter     = &mantis->adapter;
+       struct mantis_hwconfig *config  = mantis->hwconfig;
+       int err = 0;
+
+       gpio_set_bits(mantis, config->reset, 0);
+       msleep(100);
+       err = mantis_frontend_power(mantis, POWER_ON);
+       msleep(100);
+       gpio_set_bits(mantis, config->reset, 1);
+
+       err = mantis_frontend_power(mantis, POWER_ON);
+       if (err == 0) {
+               msleep(250);
+               dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)");
+               fe = zl10353_attach(&hopper_vp3028_config, adapter);
+
+               if (!fe)
+                       return -1;
+       } else {
+               dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+                       adapter->name,
+                       err);
+
+               return -EIO;
+       }
+       dprintk(MANTIS_ERROR, 1, "Done!");
+
+       return 0;
+}
+
+struct mantis_hwconfig vp3028_config = {
+       .model_name     = MANTIS_MODEL_NAME,
+       .dev_type       = MANTIS_DEV_TYPE,
+       .ts_size        = MANTIS_TS_188,
+
+       .baud_rate      = MANTIS_BAUD_9600,
+       .parity         = MANTIS_PARITY_NONE,
+       .bytes          = 0,
+
+       .frontend_init  = vp3028_frontend_init,
+       .power          = GPIF_A00,
+       .reset          = GPIF_A03,
+};
diff --git a/drivers/media/dvb/mantis/hopper_vp3028.h b/drivers/media/dvb/mantis/hopper_vp3028.h
new file mode 100644 (file)
index 0000000..5723949
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+       Hopper VP-3028 driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP3028_H
+#define __MANTIS_VP3028_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_3028_DVB_T   0x0028
+
+extern struct mantis_hwconfig vp3028_config;
+
+#endif /* __MANTIS_VP3028_H */
diff --git a/drivers/media/dvb/mantis/mantis_ca.c b/drivers/media/dvb/mantis/mantis_ca.c
new file mode 100644 (file)
index 0000000..403ce04
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_link.h"
+#include "mantis_hif.h"
+#include "mantis_reg.h"
+
+#include "mantis_ca.h"
+
+static int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr)
+{
+       struct mantis_ca *ca = en50221->data;
+       struct mantis_pci *mantis = ca->ca_priv;
+
+       dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read", slot);
+
+       if (slot != 0)
+               return -EINVAL;
+
+       return mantis_hif_read_mem(ca, addr);
+}
+
+static int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data)
+{
+       struct mantis_ca *ca = en50221->data;
+       struct mantis_pci *mantis = ca->ca_priv;
+
+       dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write", slot);
+
+       if (slot != 0)
+               return -EINVAL;
+
+       return mantis_hif_write_mem(ca, addr, data);
+}
+
+static int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
+{
+       struct mantis_ca *ca = en50221->data;
+       struct mantis_pci *mantis = ca->ca_priv;
+
+       dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read", slot);
+
+       if (slot != 0)
+               return -EINVAL;
+
+       return mantis_hif_read_iom(ca, addr);
+}
+
+static int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data)
+{
+       struct mantis_ca *ca = en50221->data;
+       struct mantis_pci *mantis = ca->ca_priv;
+
+       dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write", slot);
+
+       if (slot != 0)
+               return -EINVAL;
+
+       return mantis_hif_write_iom(ca, addr, data);
+}
+
+static int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
+{
+       struct mantis_ca *ca = en50221->data;
+       struct mantis_pci *mantis = ca->ca_priv;
+
+       dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET", slot);
+       udelay(500); /* Wait.. */
+       mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */
+       udelay(500);
+       mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */
+       msleep(1000);
+       dvb_ca_en50221_camready_irq(&ca->en50221, 0);
+
+       return 0;
+}
+
+static int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
+{
+       struct mantis_ca *ca = en50221->data;
+       struct mantis_pci *mantis = ca->ca_priv;
+
+       dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown", slot);
+
+       return 0;
+}
+
+static int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot)
+{
+       struct mantis_ca *ca = en50221->data;
+       struct mantis_pci *mantis = ca->ca_priv;
+
+       dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot);
+/*     mantis_set_direction(mantis, 1); */ /* Enable TS through CAM */
+
+       return 0;
+}
+
+static int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open)
+{
+       struct mantis_ca *ca = en50221->data;
+       struct mantis_pci *mantis = ca->ca_priv;
+
+       dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status", slot);
+
+       if (ca->slot_state == MODULE_INSERTED) {
+               dprintk(MANTIS_DEBUG, 1, "CA Module present and ready");
+               return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+       } else {
+               dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready");
+       }
+
+       return 0;
+}
+
+int mantis_ca_init(struct mantis_pci *mantis)
+{
+       struct dvb_adapter *dvb_adapter = &mantis->dvb_adapter;
+       struct mantis_ca *ca;
+       int ca_flags = 0, result;
+
+       dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA");
+       ca = kzalloc(sizeof(struct mantis_ca), GFP_KERNEL);
+       if (!ca) {
+               dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting ..");
+               result = -ENOMEM;
+               goto err;
+       }
+
+       ca->ca_priv             = mantis;
+       mantis->mantis_ca       = ca;
+       ca_flags                = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE;
+       /* register CA interface */
+       ca->en50221.owner               = THIS_MODULE;
+       ca->en50221.read_attribute_mem  = mantis_ca_read_attr_mem;
+       ca->en50221.write_attribute_mem = mantis_ca_write_attr_mem;
+       ca->en50221.read_cam_control    = mantis_ca_read_cam_ctl;
+       ca->en50221.write_cam_control   = mantis_ca_write_cam_ctl;
+       ca->en50221.slot_reset          = mantis_ca_slot_reset;
+       ca->en50221.slot_shutdown       = mantis_ca_slot_shutdown;
+       ca->en50221.slot_ts_enable      = mantis_ts_control;
+       ca->en50221.poll_slot_status    = mantis_slot_status;
+       ca->en50221.data                = ca;
+
+       mutex_init(&ca->ca_lock);
+
+       init_waitqueue_head(&ca->hif_data_wq);
+       init_waitqueue_head(&ca->hif_opdone_wq);
+       init_waitqueue_head(&ca->hif_write_wq);
+
+       dprintk(MANTIS_ERROR, 1, "Registering EN50221 device");
+       result = dvb_ca_en50221_init(dvb_adapter, &ca->en50221, ca_flags, 1);
+       if (result != 0) {
+               dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>", result);
+               goto err;
+       }
+       dprintk(MANTIS_ERROR, 1, "Registered EN50221 device");
+       mantis_evmgr_init(ca);
+       return 0;
+err:
+       kfree(ca);
+       return result;
+}
+EXPORT_SYMBOL_GPL(mantis_ca_init);
+
+void mantis_ca_exit(struct mantis_pci *mantis)
+{
+       struct mantis_ca *ca = mantis->mantis_ca;
+
+       dprintk(MANTIS_DEBUG, 1, "Mantis CA exit");
+
+       mantis_evmgr_exit(ca);
+       dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device");
+       if (ca)
+               dvb_ca_en50221_release(&ca->en50221);
+
+       kfree(ca);
+}
+EXPORT_SYMBOL_GPL(mantis_ca_exit);
diff --git a/drivers/media/dvb/mantis/mantis_ca.h b/drivers/media/dvb/mantis/mantis_ca.h
new file mode 100644 (file)
index 0000000..dc63e55
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_CA_H
+#define __MANTIS_CA_H
+
+extern int mantis_ca_init(struct mantis_pci *mantis);
+extern void mantis_ca_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_CA_H */
diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c
new file mode 100644 (file)
index 0000000..16f1708
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/irq.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+
+#include "mantis_vp1033.h"
+#include "mantis_vp1034.h"
+#include "mantis_vp1041.h"
+#include "mantis_vp2033.h"
+#include "mantis_vp2040.h"
+#include "mantis_vp3030.h"
+
+#include "mantis_dma.h"
+#include "mantis_ca.h"
+#include "mantis_dvb.h"
+#include "mantis_uart.h"
+#include "mantis_ioc.h"
+#include "mantis_pci.h"
+#include "mantis_i2c.h"
+#include "mantis_reg.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+
+static int devs;
+
+#define DRIVER_NAME    "Mantis"
+
+static char *label[10] = {
+       "DMA",
+       "IRQ-0",
+       "IRQ-1",
+       "OCERR",
+       "PABRT",
+       "RIPRR",
+       "PPERR",
+       "FTRGT",
+       "RISCI",
+       "RACK"
+};
+
+static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
+{
+       u32 stat = 0, mask = 0, lstat = 0, mstat = 0;
+       u32 rst_stat = 0, rst_mask = 0;
+
+       struct mantis_pci *mantis;
+       struct mantis_ca *ca;
+
+       mantis = (struct mantis_pci *) dev_id;
+       if (unlikely(mantis == NULL)) {
+               dprintk(MANTIS_ERROR, 1, "Mantis == NULL");
+               return IRQ_NONE;
+       }
+       ca = mantis->mantis_ca;
+
+       stat = mmread(MANTIS_INT_STAT);
+       mask = mmread(MANTIS_INT_MASK);
+       mstat = lstat = stat & ~MANTIS_INT_RISCSTAT;
+       if (!(stat & mask))
+               return IRQ_NONE;
+
+       rst_mask  = MANTIS_GPIF_WRACK  |
+                   MANTIS_GPIF_OTHERR |
+                   MANTIS_SBUF_WSTO   |
+                   MANTIS_GPIF_EXTIRQ;
+
+       rst_stat  = mmread(MANTIS_GPIF_STATUS);
+       rst_stat &= rst_mask;
+       mmwrite(rst_stat, MANTIS_GPIF_STATUS);
+
+       mantis->mantis_int_stat = stat;
+       mantis->mantis_int_mask = mask;
+       dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask);
+       if (stat & MANTIS_INT_RISCEN) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]);
+       }
+       if (stat & MANTIS_INT_IRQ0) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]);
+               mantis->gpif_status = rst_stat;
+               wake_up(&ca->hif_write_wq);
+               schedule_work(&ca->hif_evm_work);
+       }
+       if (stat & MANTIS_INT_IRQ1) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]);
+               schedule_work(&mantis->uart_work);
+       }
+       if (stat & MANTIS_INT_OCERR) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]);
+       }
+       if (stat & MANTIS_INT_PABORT) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]);
+       }
+       if (stat & MANTIS_INT_RIPERR) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]);
+       }
+       if (stat & MANTIS_INT_PPERR) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]);
+       }
+       if (stat & MANTIS_INT_FTRGT) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]);
+       }
+       if (stat & MANTIS_INT_RISCI) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
+               mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
+               tasklet_schedule(&mantis->tasklet);
+       }
+       if (stat & MANTIS_INT_I2CDONE) {
+               dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
+               wake_up(&mantis->i2c_wq);
+       }
+       mmwrite(stat, MANTIS_INT_STAT);
+       stat &= ~(MANTIS_INT_RISCEN   | MANTIS_INT_I2CDONE |
+                 MANTIS_INT_I2CRACK  | MANTIS_INT_PCMCIA7 |
+                 MANTIS_INT_PCMCIA6  | MANTIS_INT_PCMCIA5 |
+                 MANTIS_INT_PCMCIA4  | MANTIS_INT_PCMCIA3 |
+                 MANTIS_INT_PCMCIA2  | MANTIS_INT_PCMCIA1 |
+                 MANTIS_INT_PCMCIA0  | MANTIS_INT_IRQ1    |
+                 MANTIS_INT_IRQ0     | MANTIS_INT_OCERR   |
+                 MANTIS_INT_PABORT   | MANTIS_INT_RIPERR  |
+                 MANTIS_INT_PPERR    | MANTIS_INT_FTRGT   |
+                 MANTIS_INT_RISCI);
+
+       if (stat)
+               dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask);
+
+       dprintk(MANTIS_DEBUG, 0, "\n");
+       return IRQ_HANDLED;
+}
+
+static int __devinit mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+       struct mantis_pci *mantis;
+       struct mantis_hwconfig *config;
+       int err = 0;
+
+       mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL);
+       if (mantis == NULL) {
+               printk(KERN_ERR "%s ERROR: Out of memory\n", __func__);
+               err = -ENOMEM;
+               goto fail0;
+       }
+
+       mantis->num             = devs;
+       mantis->verbose         = verbose;
+       mantis->pdev            = pdev;
+       config                  = (struct mantis_hwconfig *) pci_id->driver_data;
+       config->irq_handler     = &mantis_irq_handler;
+       mantis->hwconfig        = config;
+
+       err = mantis_pci_init(mantis);
+       if (err) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err);
+               goto fail1;
+       }
+
+       err = mantis_stream_control(mantis, STREAM_TO_HIF);
+       if (err < 0) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err);
+               goto fail1;
+       }
+
+       err = mantis_i2c_init(mantis);
+       if (err < 0) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err);
+               goto fail2;
+       }
+
+       err = mantis_get_mac(mantis);
+       if (err < 0) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err);
+               goto fail2;
+       }
+
+       err = mantis_dma_init(mantis);
+       if (err < 0) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err);
+               goto fail3;
+       }
+
+       err = mantis_dvb_init(mantis);
+       if (err < 0) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err);
+               goto fail4;
+       }
+       err = mantis_uart_init(mantis);
+       if (err < 0) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err);
+               goto fail6;
+       }
+
+       devs++;
+
+       return err;
+
+
+       dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err);
+       mantis_uart_exit(mantis);
+
+fail6:
+fail4:
+       dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err);
+       mantis_dma_exit(mantis);
+
+fail3:
+       dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err);
+       mantis_i2c_exit(mantis);
+
+fail2:
+       dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err);
+       mantis_pci_exit(mantis);
+
+fail1:
+       dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err);
+       kfree(mantis);
+
+fail0:
+       return err;
+}
+
+static void __devexit mantis_pci_remove(struct pci_dev *pdev)
+{
+       struct mantis_pci *mantis = pci_get_drvdata(pdev);
+
+       if (mantis) {
+
+               mantis_uart_exit(mantis);
+               mantis_dvb_exit(mantis);
+               mantis_dma_exit(mantis);
+               mantis_i2c_exit(mantis);
+               mantis_pci_exit(mantis);
+               kfree(mantis);
+       }
+       return;
+}
+
+static struct pci_device_id mantis_pci_table[] = {
+       MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config),
+       MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config),
+       MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config),
+       MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config),
+       MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config),
+       MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config),
+       MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config),
+       MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config),
+       MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config),
+       MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2033_config),
+       MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config),
+       { }
+};
+
+static struct pci_driver mantis_pci_driver = {
+       .name           = DRIVER_NAME,
+       .id_table       = mantis_pci_table,
+       .probe          = mantis_pci_probe,
+       .remove         = mantis_pci_remove,
+};
+
+static int __devinit mantis_init(void)
+{
+       return pci_register_driver(&mantis_pci_driver);
+}
+
+static void __devexit mantis_exit(void)
+{
+       return pci_unregister_driver(&mantis_pci_driver);
+}
+
+module_init(mantis_init);
+module_exit(mantis_exit);
+
+MODULE_DESCRIPTION("MANTIS driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/mantis_common.h b/drivers/media/dvb/mantis/mantis_common.h
new file mode 100644 (file)
index 0000000..d0b645a
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_COMMON_H
+#define __MANTIS_COMMON_H
+
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#include "mantis_uart.h"
+
+#include "mantis_link.h"
+
+#define MANTIS_ERROR           0
+#define MANTIS_NOTICE          1
+#define MANTIS_INFO            2
+#define MANTIS_DEBUG           3
+#define MANTIS_TMG             9
+
+#define dprintk(y, z, format, arg...) do {                                                             \
+       if (z) {                                                                                        \
+               if      ((mantis->verbose > MANTIS_ERROR) && (mantis->verbose > y))                     \
+                       printk(KERN_ERR "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);      \
+               else if ((mantis->verbose > MANTIS_NOTICE) && (mantis->verbose > y))                    \
+                       printk(KERN_NOTICE "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);   \
+               else if ((mantis->verbose > MANTIS_INFO) && (mantis->verbose > y))                      \
+                       printk(KERN_INFO "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);     \
+               else if ((mantis->verbose > MANTIS_DEBUG) && (mantis->verbose > y))                     \
+                       printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);    \
+               else if ((mantis->verbose > MANTIS_TMG) && (mantis->verbose > y))                       \
+                       printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg);    \
+       } else {                                                                                        \
+               if (mantis->verbose > y)                                                                \
+                       printk(format , ##arg);                                                         \
+       }                                                                                               \
+} while(0)
+
+#define mwrite(dat, addr)      writel((dat), addr)
+#define mread(addr)            readl(addr)
+
+#define mmwrite(dat, addr)     mwrite((dat), (mantis->mmio + (addr)))
+#define mmread(addr)           mread(mantis->mmio + (addr))
+
+#define MANTIS_TS_188          0
+#define MANTIS_TS_204          1
+
+#define TWINHAN_TECHNOLOGIES   0x1822
+#define MANTIS                 0x4e35
+
+#define TECHNISAT              0x1ae4
+#define TERRATEC               0x153b
+
+#define MAKE_ENTRY(__subven, __subdev, __configptr) {                  \
+               .vendor         = TWINHAN_TECHNOLOGIES,                 \
+               .device         = MANTIS,                               \
+               .subvendor      = (__subven),                           \
+               .subdevice      = (__subdev),                           \
+               .driver_data    = (unsigned long) (__configptr)         \
+}
+
+enum mantis_i2c_mode {
+       MANTIS_PAGE_MODE = 0,
+       MANTIS_BYTE_MODE,
+};
+
+struct mantis_pci;
+
+struct mantis_hwconfig {
+       char                    *model_name;
+       char                    *dev_type;
+       u32                     ts_size;
+
+       enum mantis_baud        baud_rate;
+       enum mantis_parity      parity;
+       u32                     bytes;
+
+       irqreturn_t (*irq_handler)(int irq, void *dev_id);
+       int (*frontend_init)(struct mantis_pci *mantis, struct dvb_frontend *fe);
+
+       u8                      power;
+       u8                      reset;
+
+       enum mantis_i2c_mode    i2c_mode;
+};
+
+struct mantis_pci {
+       unsigned int            verbose;
+
+       /*      PCI stuff               */
+       u16                     vendor_id;
+       u16                     device_id;
+       u16                     subsystem_vendor;
+       u16                     subsystem_device;
+
+       u8                      latency;
+
+       struct pci_dev          *pdev;
+
+       unsigned long           mantis_addr;
+       void __iomem            *mmio;
+
+       u8                      irq;
+       u8                      revision;
+
+       unsigned int            num;
+
+       /*      RISC Core               */
+       u32                     finished_block;
+       u32                     last_block;
+       u32                     line_bytes;
+       u32                     line_count;
+       u32                     risc_pos;
+       u8                      *buf_cpu;
+       dma_addr_t              buf_dma;
+       u32                     *risc_cpu;
+       dma_addr_t              risc_dma;
+
+       struct tasklet_struct   tasklet;
+
+       struct i2c_adapter      adapter;
+       int                     i2c_rc;
+       wait_queue_head_t       i2c_wq;
+       struct mutex            i2c_lock;
+
+       /*      DVB stuff               */
+       struct dvb_adapter      dvb_adapter;
+       struct dvb_frontend     *fe;
+       struct dvb_demux        demux;
+       struct dmxdev           dmxdev;
+       struct dmx_frontend     fe_hw;
+       struct dmx_frontend     fe_mem;
+       struct dvb_net          dvbnet;
+
+       u8                      feeds;
+
+       struct mantis_hwconfig  *hwconfig;
+
+       u32                     mantis_int_stat;
+       u32                     mantis_int_mask;
+
+       /*      board specific          */
+       u8                      mac_address[8];
+       u32                     sub_vendor_id;
+       u32                     sub_device_id;
+
+        /*     A12 A13 A14             */
+       u32                     gpio_status;
+
+       u32                     gpif_status;
+
+       struct mantis_ca        *mantis_ca;
+
+       wait_queue_head_t       uart_wq;
+       struct work_struct      uart_work;
+       spinlock_t              uart_lock;
+
+       struct input_dev        *rc;
+};
+
+#define MANTIS_HIF_STATUS      (mantis->gpio_status)
+
+#endif /* __MANTIS_COMMON_H */
diff --git a/drivers/media/dvb/mantis/mantis_core.c b/drivers/media/dvb/mantis/mantis_core.c
new file mode 100644 (file)
index 0000000..8113b23
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "mantis_common.h"
+#include "mantis_core.h"
+#include "mantis_vp1033.h"
+#include "mantis_vp1034.h"
+#include "mantis_vp1041.h"
+#include "mantis_vp2033.h"
+#include "mantis_vp2040.h"
+#include "mantis_vp3030.h"
+
+static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
+{
+       int err;
+       struct i2c_msg msg[] = {
+               {
+                       .addr = 0x50,
+                       .flags = 0,
+                       .buf = data,
+                       .len = 1
+               }, {
+                       .addr = 0x50,
+                       .flags = I2C_M_RD,
+                       .buf = data,
+                       .len = length
+               },
+       };
+
+       err = i2c_transfer(&mantis->adapter, msg, 2);
+       if (err < 0) {
+               dprintk(verbose, MANTIS_ERROR, 1,
+                       "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >",
+                       err, data[0], data[1]);
+
+               return err;
+       }
+
+       return 0;
+}
+
+static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
+{
+       int err;
+
+       struct i2c_msg msg = {
+               .addr = 0x50,
+               .flags = 0,
+               .buf = data,
+               .len = length
+       };
+
+       err = i2c_transfer(&mantis->adapter, &msg, 1);
+       if (err < 0) {
+               dprintk(verbose, MANTIS_ERROR, 1,
+                       "ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >",
+                       err, length, data[0], data[1]);
+
+               return err;
+       }
+
+       return 0;
+}
+
+static int get_mac_address(struct mantis_pci *mantis)
+{
+       int err;
+
+       mantis->mac_address[0] = 0x08;
+       err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6);
+       if (err < 0) {
+               dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error");
+
+               return err;
+       }
+       dprintk(verbose, MANTIS_ERROR, 0,
+               "    MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+               mantis->mac_address[0], mantis->mac_address[1],
+               mantis->mac_address[2], mantis->mac_address[3],
+               mantis->mac_address[4], mantis->mac_address[5]);
+
+       return 0;
+}
+
+#define MANTIS_MODEL_UNKNOWN   "UNKNOWN"
+#define MANTIS_DEV_UNKNOWN     "UNKNOWN"
+
+struct mantis_hwconfig unknown_device = {
+       .model_name     = MANTIS_MODEL_UNKNOWN,
+       .dev_type       = MANTIS_DEV_UNKNOWN,
+};
+
+static void mantis_load_config(struct mantis_pci *mantis)
+{
+       switch (mantis->subsystem_device) {
+       case MANTIS_VP_1033_DVB_S:      /* VP-1033 */
+               mantis->hwconfig = &vp1033_mantis_config;
+               break;
+       case MANTIS_VP_1034_DVB_S:      /* VP-1034 */
+               mantis->hwconfig = &vp1034_mantis_config;
+               break;
+       case MANTIS_VP_1041_DVB_S2:     /* VP-1041 */
+       case TECHNISAT_SKYSTAR_HD2:
+               mantis->hwconfig = &vp1041_mantis_config;
+               break;
+       case MANTIS_VP_2033_DVB_C:      /* VP-2033 */
+               mantis->hwconfig = &vp2033_mantis_config;
+               break;
+       case MANTIS_VP_2040_DVB_C:      /* VP-2040 */
+       case TERRATEC_CINERGY_C_PCI:    /* VP-2040 clone */
+       case TECHNISAT_CABLESTAR_HD2:
+               mantis->hwconfig = &vp2040_mantis_config;
+               break;
+       case MANTIS_VP_3030_DVB_T:      /* VP-3030 */
+               mantis->hwconfig = &vp3030_mantis_config;
+               break;
+       default:
+               mantis->hwconfig = &unknown_device;
+               break;
+       }
+}
+
+int mantis_core_init(struct mantis_pci *mantis)
+{
+       int err = 0;
+
+       mantis_load_config(mantis);
+       dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n",
+               mantis->hwconfig->model_name, mantis->hwconfig->dev_type,
+               mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn));
+       dprintk(verbose, MANTIS_ERROR, 0, "    Mantis Rev %d [%04x:%04x], ",
+               mantis->revision,
+               mantis->subsystem_vendor, mantis->subsystem_device);
+       dprintk(verbose, MANTIS_ERROR, 0,
+               "irq: %d, latency: %d\n    memory: 0x%lx, mmio: 0x%p\n",
+               mantis->pdev->irq, mantis->latency,
+               mantis->mantis_addr, mantis->mantis_mmio);
+
+       err = mantis_i2c_init(mantis);
+       if (err < 0) {
+               dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed");
+               return err;
+       }
+       err = get_mac_address(mantis);
+       if (err < 0) {
+               dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed");
+               return err;
+       }
+       err = mantis_dma_init(mantis);
+       if (err < 0) {
+               dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed");
+               return err;
+       }
+       err = mantis_dvb_init(mantis);
+       if (err < 0) {
+               dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed");
+               return err;
+       }
+       err = mantis_uart_init(mantis);
+       if (err < 0) {
+               dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed");
+               return err;
+       }
+
+       return 0;
+}
+
+int mantis_core_exit(struct mantis_pci *mantis)
+{
+       mantis_dma_stop(mantis);
+       dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping");
+
+       mantis_uart_exit(mantis);
+       dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed");
+
+       if (mantis_dma_exit(mantis) < 0)
+               dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed");
+       if (mantis_dvb_exit(mantis) < 0)
+               dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed");
+       if (mantis_i2c_exit(mantis) < 0)
+               dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed");
+
+       return 0;
+}
+
+/* Turn the given bit on or off. */
+void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
+{
+       u32 cur;
+
+       cur = mmread(MANTIS_GPIF_ADDR);
+       if (value)
+               mantis->gpio_status = cur | (1 << bitpos);
+       else
+               mantis->gpio_status = cur & (~(1 << bitpos));
+
+       mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
+       mmwrite(0x00, MANTIS_GPIF_DOUT);
+       udelay(100);
+}
+
+/* direction = 0 , no CI passthrough ; 1 , CI passthrough */
+void mantis_set_direction(struct mantis_pci *mantis, int direction)
+{
+       u32 reg;
+
+       reg = mmread(0x28);
+       dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup");
+       if (direction == 0x01) {
+               /* to CI */
+               reg |= 0x04;
+               mmwrite(reg, 0x28);
+               reg &= 0xff - 0x04;
+               mmwrite(reg, 0x28);
+       } else {
+               reg &= 0xff - 0x04;
+               mmwrite(reg, 0x28);
+               reg |= 0x04;
+               mmwrite(reg, 0x28);
+       }
+}
diff --git a/drivers/media/dvb/mantis/mantis_core.h b/drivers/media/dvb/mantis/mantis_core.h
new file mode 100644 (file)
index 0000000..833ee42
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_CORE_H
+#define __MANTIS_CORE_H
+
+#include "mantis_common.h"
+
+
+#define FE_TYPE_SAT    0
+#define FE_TYPE_CAB    1
+#define FE_TYPE_TER    2
+
+#define FE_TYPE_TS204  0
+#define FE_TYPE_TS188  1
+
+
+struct vendorname {
+       u8  *sub_vendor_name;
+       u32 sub_vendor_id;
+};
+
+struct devicetype {
+       u8  *sub_device_name;
+       u32 sub_device_id;
+       u8  device_type;
+       u32 type_flags;
+};
+
+
+extern int mantis_dma_init(struct mantis_pci *mantis);
+extern int mantis_dma_exit(struct mantis_pci *mantis);
+extern void mantis_dma_start(struct mantis_pci *mantis);
+extern void mantis_dma_stop(struct mantis_pci *mantis);
+extern int mantis_i2c_init(struct mantis_pci *mantis);
+extern int mantis_i2c_exit(struct mantis_pci *mantis);
+extern int mantis_core_init(struct mantis_pci *mantis);
+extern int mantis_core_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_CORE_H */
diff --git a/drivers/media/dvb/mantis/mantis_dma.c b/drivers/media/dvb/mantis/mantis_dma.c
new file mode 100644 (file)
index 0000000..46202a4
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <asm/page.h>
+#include <linux/vmalloc.h>
+#include <linux/pci.h>
+
+#include <asm/irq.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_dma.h"
+
+#define RISC_WRITE             (0x01 << 28)
+#define RISC_JUMP              (0x07 << 28)
+#define RISC_IRQ               (0x01 << 24)
+
+#define RISC_STATUS(status)    ((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16))
+#define RISC_FLUSH()           (mantis->risc_pos = 0)
+#define RISC_INSTR(opcode)     (mantis->risc_cpu[mantis->risc_pos++] = cpu_to_le32(opcode))
+
+#define MANTIS_BUF_SIZE                (64 * 1024)
+#define MANTIS_BLOCK_BYTES     (MANTIS_BUF_SIZE >> 4)
+#define MANTIS_BLOCK_COUNT     (1 << 4)
+#define MANTIS_RISC_SIZE       PAGE_SIZE
+
+int mantis_dma_exit(struct mantis_pci *mantis)
+{
+       if (mantis->buf_cpu) {
+               dprintk(MANTIS_ERROR, 1,
+                       "DMA=0x%lx cpu=0x%p size=%d",
+                       (unsigned long) mantis->buf_dma,
+                        mantis->buf_cpu,
+                        MANTIS_BUF_SIZE);
+
+               pci_free_consistent(mantis->pdev, MANTIS_BUF_SIZE,
+                                   mantis->buf_cpu, mantis->buf_dma);
+
+               mantis->buf_cpu = NULL;
+       }
+       if (mantis->risc_cpu) {
+               dprintk(MANTIS_ERROR, 1,
+                       "RISC=0x%lx cpu=0x%p size=%lx",
+                       (unsigned long) mantis->risc_dma,
+                       mantis->risc_cpu,
+                       MANTIS_RISC_SIZE);
+
+               pci_free_consistent(mantis->pdev, MANTIS_RISC_SIZE,
+                                   mantis->risc_cpu, mantis->risc_dma);
+
+               mantis->risc_cpu = NULL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_dma_exit);
+
+static inline int mantis_alloc_buffers(struct mantis_pci *mantis)
+{
+       if (!mantis->buf_cpu) {
+               mantis->buf_cpu = pci_alloc_consistent(mantis->pdev,
+                                                      MANTIS_BUF_SIZE,
+                                                      &mantis->buf_dma);
+               if (!mantis->buf_cpu) {
+                       dprintk(MANTIS_ERROR, 1,
+                               "DMA buffer allocation failed");
+
+                       goto err;
+               }
+               dprintk(MANTIS_ERROR, 1,
+                       "DMA=0x%lx cpu=0x%p size=%d",
+                       (unsigned long) mantis->buf_dma,
+                       mantis->buf_cpu, MANTIS_BUF_SIZE);
+       }
+       if (!mantis->risc_cpu) {
+               mantis->risc_cpu = pci_alloc_consistent(mantis->pdev,
+                                                       MANTIS_RISC_SIZE,
+                                                       &mantis->risc_dma);
+
+               if (!mantis->risc_cpu) {
+                       dprintk(MANTIS_ERROR, 1,
+                               "RISC program allocation failed");
+
+                       mantis_dma_exit(mantis);
+
+                       goto err;
+               }
+               dprintk(MANTIS_ERROR, 1,
+                       "RISC=0x%lx cpu=0x%p size=%lx",
+                       (unsigned long) mantis->risc_dma,
+                       mantis->risc_cpu, MANTIS_RISC_SIZE);
+       }
+
+       return 0;
+err:
+       dprintk(MANTIS_ERROR, 1, "Out of memory (?) .....");
+       return -ENOMEM;
+}
+
+static inline int mantis_calc_lines(struct mantis_pci *mantis)
+{
+       mantis->line_bytes = MANTIS_BLOCK_BYTES;
+       mantis->line_count = MANTIS_BLOCK_COUNT;
+
+       while (mantis->line_bytes > 4095) {
+               mantis->line_bytes >>= 1;
+               mantis->line_count <<= 1;
+       }
+
+       dprintk(MANTIS_DEBUG, 1, "Mantis RISC block bytes=[%d], line bytes=[%d], line count=[%d]",
+               MANTIS_BLOCK_BYTES, mantis->line_bytes, mantis->line_count);
+
+       if (mantis->line_count > 255) {
+               dprintk(MANTIS_ERROR, 1, "Buffer size error");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int mantis_dma_init(struct mantis_pci *mantis)
+{
+       int err = 0;
+
+       dprintk(MANTIS_DEBUG, 1, "Mantis DMA init");
+       if (mantis_alloc_buffers(mantis) < 0) {
+               dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer");
+
+               /* Stop RISC Engine */
+               mmwrite(0, MANTIS_DMA_CTL);
+
+               goto err;
+       }
+       err = mantis_calc_lines(mantis);
+       if (err < 0) {
+               dprintk(MANTIS_ERROR, 1, "Mantis calc lines failed");
+
+               goto err;
+       }
+
+       return 0;
+err:
+       return err;
+}
+EXPORT_SYMBOL_GPL(mantis_dma_init);
+
+static inline void mantis_risc_program(struct mantis_pci *mantis)
+{
+       u32 buf_pos = 0;
+       u32 line;
+
+       dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program");
+       RISC_FLUSH();
+
+       dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u",
+               mantis->line_count, mantis->line_bytes);
+
+       for (line = 0; line < mantis->line_count; line++) {
+               dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d]", line);
+               if (!(buf_pos % MANTIS_BLOCK_BYTES)) {
+                       RISC_INSTR(RISC_WRITE   |
+                                  RISC_IRQ     |
+                                  RISC_STATUS(((buf_pos / MANTIS_BLOCK_BYTES) +
+                                  (MANTIS_BLOCK_COUNT - 1)) %
+                                   MANTIS_BLOCK_COUNT) |
+                                   mantis->line_bytes);
+               } else {
+                       RISC_INSTR(RISC_WRITE   | mantis->line_bytes);
+               }
+               RISC_INSTR(mantis->buf_dma + buf_pos);
+               buf_pos += mantis->line_bytes;
+       }
+       RISC_INSTR(RISC_JUMP);
+       RISC_INSTR(mantis->risc_dma);
+}
+
+void mantis_dma_start(struct mantis_pci *mantis)
+{
+       dprintk(MANTIS_DEBUG, 1, "Mantis Start DMA engine");
+
+       mantis_risc_program(mantis);
+       mmwrite(mantis->risc_dma, MANTIS_RISC_START);
+       mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
+
+       mmwrite(0, MANTIS_DMA_CTL);
+       mantis->last_block = mantis->finished_block = 0;
+
+       mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK);
+
+       mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN
+                              | MANTIS_RISC_EN, MANTIS_DMA_CTL);
+
+}
+
+void mantis_dma_stop(struct mantis_pci *mantis)
+{
+       u32 stat = 0, mask = 0;
+
+       stat = mmread(MANTIS_INT_STAT);
+       mask = mmread(MANTIS_INT_MASK);
+       dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine");
+
+       mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR);
+
+       mmwrite((mmread(MANTIS_DMA_CTL) & ~(MANTIS_FIFO_EN |
+                                           MANTIS_DCAP_EN |
+                                           MANTIS_RISC_EN)), MANTIS_DMA_CTL);
+
+       mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT);
+
+       mmwrite(mmread(MANTIS_INT_MASK) & ~(MANTIS_INT_RISCI |
+                                           MANTIS_INT_RISCEN), MANTIS_INT_MASK);
+}
+
+
+void mantis_dma_xfer(unsigned long data)
+{
+       struct mantis_pci *mantis = (struct mantis_pci *) data;
+       struct mantis_hwconfig *config = mantis->hwconfig;
+
+       while (mantis->last_block != mantis->finished_block) {
+               dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]",
+                       mantis->last_block, mantis->finished_block);
+
+               (config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
+               (&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES);
+               mantis->last_block = (mantis->last_block + 1) % MANTIS_BLOCK_COUNT;
+       }
+}
diff --git a/drivers/media/dvb/mantis/mantis_dma.h b/drivers/media/dvb/mantis/mantis_dma.h
new file mode 100644 (file)
index 0000000..6be00fa
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_DMA_H
+#define __MANTIS_DMA_H
+
+extern int mantis_dma_init(struct mantis_pci *mantis);
+extern int mantis_dma_exit(struct mantis_pci *mantis);
+extern void mantis_dma_start(struct mantis_pci *mantis);
+extern void mantis_dma_stop(struct mantis_pci *mantis);
+extern void mantis_dma_xfer(unsigned long data);
+
+#endif /* __MANTIS_DMA_H */
diff --git a/drivers/media/dvb/mantis/mantis_dvb.c b/drivers/media/dvb/mantis/mantis_dvb.c
new file mode 100644 (file)
index 0000000..99d82ee
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+       Mantis PCI bridge driver
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_dma.h"
+#include "mantis_ca.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power)
+{
+       struct mantis_hwconfig *config = mantis->hwconfig;
+
+       switch (power) {
+       case POWER_ON:
+               dprintk(MANTIS_DEBUG, 1, "Power ON");
+               gpio_set_bits(mantis, config->power, POWER_ON);
+               msleep(100);
+               gpio_set_bits(mantis, config->power, POWER_ON);
+               msleep(100);
+               break;
+
+       case POWER_OFF:
+               dprintk(MANTIS_DEBUG, 1, "Power OFF");
+               gpio_set_bits(mantis, config->power, POWER_OFF);
+               msleep(100);
+               break;
+
+       default:
+               dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power);
+               return -1;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_frontend_power);
+
+void mantis_frontend_soft_reset(struct mantis_pci *mantis)
+{
+       struct mantis_hwconfig *config = mantis->hwconfig;
+
+       dprintk(MANTIS_DEBUG, 1, "Frontend RESET");
+       gpio_set_bits(mantis, config->reset, 0);
+       msleep(100);
+       gpio_set_bits(mantis, config->reset, 0);
+       msleep(100);
+       gpio_set_bits(mantis, config->reset, 1);
+       msleep(100);
+       gpio_set_bits(mantis, config->reset, 1);
+       msleep(100);
+
+       return;
+}
+EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset);
+
+static int mantis_frontend_shutdown(struct mantis_pci *mantis)
+{
+       int err;
+
+       mantis_frontend_soft_reset(mantis);
+       err = mantis_frontend_power(mantis, POWER_OFF);
+       if (err != 0) {
+               dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+       struct mantis_pci *mantis = dvbdmx->priv;
+
+       dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed");
+       if (!dvbdmx->dmx.frontend) {
+               dprintk(MANTIS_DEBUG, 1, "no frontend ?");
+               return -EINVAL;
+       }
+
+       mantis->feeds++;
+       dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d", mantis->feeds);
+
+       if (mantis->feeds == 1)  {
+               dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
+               mantis_dma_start(mantis);
+       }
+
+       return mantis->feeds;
+}
+
+static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+       struct mantis_pci *mantis = dvbdmx->priv;
+
+       dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed");
+       if (!dvbdmx->dmx.frontend) {
+               dprintk(MANTIS_DEBUG, 1, "no frontend ?");
+               return -EINVAL;
+       }
+
+       mantis->feeds--;
+       if (mantis->feeds == 0) {
+               dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
+               mantis_dma_stop(mantis);
+       }
+
+       return 0;
+}
+
+int __devinit mantis_dvb_init(struct mantis_pci *mantis)
+{
+       struct mantis_hwconfig *config = mantis->hwconfig;
+       int result = -1;
+
+       dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter");
+
+       result = dvb_register_adapter(&mantis->dvb_adapter,
+                                     "Mantis DVB adapter",
+                                     THIS_MODULE,
+                                     &mantis->pdev->dev,
+                                     adapter_nr);
+
+       if (result < 0) {
+
+               dprintk(MANTIS_ERROR, 1, "Error registering adapter");
+               return -ENODEV;
+       }
+
+       mantis->dvb_adapter.priv        = mantis;
+       mantis->demux.dmx.capabilities  = DMX_TS_FILTERING      |
+                                        DMX_SECTION_FILTERING  |
+                                        DMX_MEMORY_BASED_FILTERING;
+
+       mantis->demux.priv              = mantis;
+       mantis->demux.filternum         = 256;
+       mantis->demux.feednum           = 256;
+       mantis->demux.start_feed        = mantis_dvb_start_feed;
+       mantis->demux.stop_feed         = mantis_dvb_stop_feed;
+       mantis->demux.write_to_decoder  = NULL;
+
+       dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init");
+       result = dvb_dmx_init(&mantis->demux);
+       if (result < 0) {
+               dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+
+               goto err0;
+       }
+
+       mantis->dmxdev.filternum        = 256;
+       mantis->dmxdev.demux            = &mantis->demux.dmx;
+       mantis->dmxdev.capabilities     = 0;
+       dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init");
+
+       result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter);
+       if (result < 0) {
+
+               dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result);
+               goto err1;
+       }
+
+       mantis->fe_hw.source            = DMX_FRONTEND_0;
+       result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+       if (result < 0) {
+
+               dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+               goto err2;
+       }
+
+       mantis->fe_mem.source           = DMX_MEMORY_FE;
+       result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+       if (result < 0) {
+               dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+               goto err3;
+       }
+
+       result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+       if (result < 0) {
+               dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+               goto err4;
+       }
+
+       dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
+       tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis);
+       if (mantis->hwconfig) {
+               result = config->frontend_init(mantis, mantis->fe);
+               if (result < 0) {
+                       dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!");
+                       goto err5;
+               } else {
+                       if (mantis->fe == NULL) {
+                               dprintk(MANTIS_ERROR, 1, "FE <NULL>");
+                               goto err5;
+                       }
+
+                       if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) {
+                               dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed");
+
+                               if (mantis->fe->ops.release)
+                                       mantis->fe->ops.release(mantis->fe);
+
+                               mantis->fe = NULL;
+                               goto err5;
+                       }
+               }
+       }
+
+       return 0;
+
+       /* Error conditions ..  */
+err5:
+       tasklet_kill(&mantis->tasklet);
+       dvb_net_release(&mantis->dvbnet);
+       dvb_unregister_frontend(mantis->fe);
+       dvb_frontend_detach(mantis->fe);
+err4:
+       mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+
+err3:
+       mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+
+err2:
+       dvb_dmxdev_release(&mantis->dmxdev);
+
+err1:
+       dvb_dmx_release(&mantis->demux);
+
+err0:
+       dvb_unregister_adapter(&mantis->dvb_adapter);
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(mantis_dvb_init);
+
+int __devexit mantis_dvb_exit(struct mantis_pci *mantis)
+{
+       int err;
+
+       if (mantis->fe) {
+               /* mantis_ca_exit(mantis); */
+               err = mantis_frontend_shutdown(mantis);
+               if (err != 0)
+                       dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err);
+               dvb_unregister_frontend(mantis->fe);
+               dvb_frontend_detach(mantis->fe);
+       }
+
+       tasklet_kill(&mantis->tasklet);
+       dvb_net_release(&mantis->dvbnet);
+
+       mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+       mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+
+       dvb_dmxdev_release(&mantis->dmxdev);
+       dvb_dmx_release(&mantis->demux);
+
+       dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter");
+       dvb_unregister_adapter(&mantis->dvb_adapter);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_dvb_exit);
diff --git a/drivers/media/dvb/mantis/mantis_dvb.h b/drivers/media/dvb/mantis/mantis_dvb.h
new file mode 100644 (file)
index 0000000..464199d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_DVB_H
+#define __MANTIS_DVB_H
+
+enum mantis_power {
+       POWER_OFF       = 0,
+       POWER_ON        = 1
+};
+
+extern int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power);
+extern void mantis_frontend_soft_reset(struct mantis_pci *mantis);
+
+extern int mantis_dvb_init(struct mantis_pci *mantis);
+extern int mantis_dvb_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_DVB_H */
diff --git a/drivers/media/dvb/mantis/mantis_evm.c b/drivers/media/dvb/mantis/mantis_evm.c
new file mode 100644 (file)
index 0000000..a7b369a
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_link.h"
+#include "mantis_hif.h"
+#include "mantis_reg.h"
+
+static void mantis_hifevm_work(struct work_struct *work)
+{
+       struct mantis_ca *ca = container_of(work, struct mantis_ca, hif_evm_work);
+       struct mantis_pci *mantis = ca->ca_priv;
+
+       u32 gpif_stat, gpif_mask;
+
+       gpif_stat = mmread(MANTIS_GPIF_STATUS);
+       gpif_mask = mmread(MANTIS_GPIF_IRQCFG);
+
+       if (gpif_stat & MANTIS_GPIF_DETSTAT) {
+               if (gpif_stat & MANTIS_CARD_PLUGIN) {
+                       dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Plugin", mantis->num);
+                       mmwrite(0xdada0000, MANTIS_CARD_RESET);
+                       mantis_event_cam_plugin(ca);
+                       dvb_ca_en50221_camchange_irq(&ca->en50221,
+                                                    0,
+                                                    DVB_CA_EN50221_CAMCHANGE_INSERTED);
+               }
+       } else {
+               if (gpif_stat & MANTIS_CARD_PLUGOUT) {
+                       dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Unplug", mantis->num);
+                       mmwrite(0xdada0000, MANTIS_CARD_RESET);
+                       mantis_event_cam_unplug(ca);
+                       dvb_ca_en50221_camchange_irq(&ca->en50221,
+                                                    0,
+                                                    DVB_CA_EN50221_CAMCHANGE_REMOVED);
+               }
+       }
+
+       if (mantis->gpif_status & MANTIS_GPIF_EXTIRQ)
+               dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Ext IRQ", mantis->num);
+
+       if (mantis->gpif_status & MANTIS_SBUF_WSTO)
+               dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Timeout", mantis->num);
+
+       if (mantis->gpif_status & MANTIS_GPIF_OTHERR)
+               dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Alignment Error", mantis->num);
+
+       if (gpif_stat & MANTIS_SBUF_OVFLW)
+               dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Overflow", mantis->num);
+
+       if (gpif_stat & MANTIS_GPIF_BRRDY)
+               dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Read Ready", mantis->num);
+
+       if (gpif_stat & MANTIS_GPIF_INTSTAT)
+               dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): GPIF IRQ", mantis->num);
+
+       if (gpif_stat & MANTIS_SBUF_EMPTY)
+               dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Empty", mantis->num);
+
+       if (gpif_stat & MANTIS_SBUF_OPDONE) {
+               dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer operation complete", mantis->num);
+               ca->sbuf_status = MANTIS_SBUF_DATA_AVAIL;
+               ca->hif_event = MANTIS_SBUF_OPDONE;
+               wake_up(&ca->hif_opdone_wq);
+       }
+}
+
+int mantis_evmgr_init(struct mantis_ca *ca)
+{
+       struct mantis_pci *mantis = ca->ca_priv;
+
+       dprintk(MANTIS_DEBUG, 1, "Initializing Mantis Host I/F Event manager");
+       INIT_WORK(&ca->hif_evm_work, mantis_hifevm_work);
+       mantis_pcmcia_init(ca);
+       schedule_work(&ca->hif_evm_work);
+       mantis_hif_init(ca);
+       return 0;
+}
+
+void mantis_evmgr_exit(struct mantis_ca *ca)
+{
+       struct mantis_pci *mantis = ca->ca_priv;
+
+       dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting");
+       flush_scheduled_work();
+       mantis_hif_exit(ca);
+       mantis_pcmcia_exit(ca);
+}
diff --git a/drivers/media/dvb/mantis/mantis_hif.c b/drivers/media/dvb/mantis/mantis_hif.c
new file mode 100644 (file)
index 0000000..7477dac
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+
+#include "mantis_hif.h"
+#include "mantis_link.h" /* temporary due to physical layer stuff */
+
+#include "mantis_reg.h"
+
+
+static int mantis_hif_sbuf_opdone_wait(struct mantis_ca *ca)
+{
+       struct mantis_pci *mantis = ca->ca_priv;
+       int rc = 0;
+
+       if (wait_event_timeout(ca->hif_opdone_wq,
+                              ca->hif_event & MANTIS_SBUF_OPDONE,
+                              msecs_to_jiffies(500)) == -ERESTARTSYS) {
+
+               dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Smart buffer operation timeout !", mantis->num);
+               rc = -EREMOTEIO;
+       }
+       dprintk(MANTIS_DEBUG, 1, "Smart Buffer Operation complete");
+       ca->hif_event &= ~MANTIS_SBUF_OPDONE;
+       return rc;
+}
+
+static int mantis_hif_write_wait(struct mantis_ca *ca)
+{
+       struct mantis_pci *mantis = ca->ca_priv;
+       u32 opdone = 0, timeout = 0;
+       int rc = 0;
+
+       if (wait_event_timeout(ca->hif_write_wq,
+                              mantis->gpif_status & MANTIS_GPIF_WRACK,
+                              msecs_to_jiffies(500)) == -ERESTARTSYS) {
+
+               dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write ACK timed out !", mantis->num);
+               rc = -EREMOTEIO;
+       }
+       dprintk(MANTIS_DEBUG, 1, "Write Acknowledged");
+       mantis->gpif_status &= ~MANTIS_GPIF_WRACK;
+       while (!opdone) {
+               opdone = (mmread(MANTIS_GPIF_STATUS) & MANTIS_SBUF_OPDONE);
+               udelay(500);
+               timeout++;
+               if (timeout > 100) {
+                       dprintk(MANTIS_ERROR, 1, "Adater(%d) Slot(0): Write operation timed out!", mantis->num);
+                       rc = -ETIMEDOUT;
+                       break;
+               }
+       }
+       dprintk(MANTIS_DEBUG, 1, "HIF Write success");
+       return rc;
+}
+
+
+int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr)
+{
+       struct mantis_pci *mantis = ca->ca_priv;
+       u32 hif_addr = 0, data, count = 4;
+
+       dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Read", mantis->num);
+       mutex_lock(&ca->ca_lock);
+       hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+       hif_addr &= ~MANTIS_GPIF_PCMCIAIOM;
+       hif_addr |=  MANTIS_HIF_STATUS;
+       hif_addr |=  addr;
+
+       mmwrite(hif_addr, MANTIS_GPIF_BRADDR);
+       mmwrite(count, MANTIS_GPIF_BRBYTES);
+       udelay(20);
+       mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
+
+       if (mantis_hif_sbuf_opdone_wait(ca) != 0) {
+               dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): GPIF Smart Buffer operation failed", mantis->num);
+               mutex_unlock(&ca->ca_lock);
+               return -EREMOTEIO;
+       }
+       data = mmread(MANTIS_GPIF_DIN);
+       mutex_unlock(&ca->ca_lock);
+       dprintk(MANTIS_DEBUG, 1, "Mem Read: 0x%02x", data);
+       return (data >> 24) & 0xff;
+}
+
+int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data)
+{
+       struct mantis_slot *slot = ca->slot;
+       struct mantis_pci *mantis = ca->ca_priv;
+       u32 hif_addr = 0;
+
+       dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Write", mantis->num);
+       mutex_lock(&ca->ca_lock);
+       hif_addr &= ~MANTIS_GPIF_HIFRDWRN;
+       hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+       hif_addr &= ~MANTIS_GPIF_PCMCIAIOM;
+       hif_addr |=  MANTIS_HIF_STATUS;
+       hif_addr |=  addr;
+
+       mmwrite(slot->slave_cfg, MANTIS_GPIF_CFGSLA); /* Slot0 alone for now */
+       mmwrite(hif_addr, MANTIS_GPIF_ADDR);
+       mmwrite(data, MANTIS_GPIF_DOUT);
+
+       if (mantis_hif_write_wait(ca) != 0) {
+               dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
+               mutex_unlock(&ca->ca_lock);
+               return -EREMOTEIO;
+       }
+       dprintk(MANTIS_DEBUG, 1, "Mem Write: (0x%02x to 0x%02x)", data, addr);
+       mutex_unlock(&ca->ca_lock);
+
+       return 0;
+}
+
+int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr)
+{
+       struct mantis_pci *mantis = ca->ca_priv;
+       u32 data, hif_addr = 0;
+
+       dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Read", mantis->num);
+       mutex_lock(&ca->ca_lock);
+       hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+       hif_addr |=  MANTIS_GPIF_PCMCIAIOM;
+       hif_addr |=  MANTIS_HIF_STATUS;
+       hif_addr |=  addr;
+
+       mmwrite(hif_addr, MANTIS_GPIF_BRADDR);
+       mmwrite(1, MANTIS_GPIF_BRBYTES);
+       udelay(20);
+       mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
+
+       if (mantis_hif_sbuf_opdone_wait(ca) != 0) {
+               dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
+               mutex_unlock(&ca->ca_lock);
+               return -EREMOTEIO;
+       }
+       data = mmread(MANTIS_GPIF_DIN);
+       dprintk(MANTIS_DEBUG, 1, "I/O Read: 0x%02x", data);
+       udelay(50);
+       mutex_unlock(&ca->ca_lock);
+
+       return (u8) data;
+}
+
+int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data)
+{
+       struct mantis_pci *mantis = ca->ca_priv;
+       u32 hif_addr = 0;
+
+       dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Write", mantis->num);
+       mutex_lock(&ca->ca_lock);
+       hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+       hif_addr &= ~MANTIS_GPIF_HIFRDWRN;
+       hif_addr |=  MANTIS_GPIF_PCMCIAIOM;
+       hif_addr |=  MANTIS_HIF_STATUS;
+       hif_addr |=  addr;
+
+       mmwrite(hif_addr, MANTIS_GPIF_ADDR);
+       mmwrite(data, MANTIS_GPIF_DOUT);
+
+       if (mantis_hif_write_wait(ca) != 0) {
+               dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
+               mutex_unlock(&ca->ca_lock);
+               return -EREMOTEIO;
+       }
+       dprintk(MANTIS_DEBUG, 1, "I/O Write: (0x%02x to 0x%02x)", data, addr);
+       mutex_unlock(&ca->ca_lock);
+       udelay(50);
+
+       return 0;
+}
+
+int mantis_hif_init(struct mantis_ca *ca)
+{
+       struct mantis_slot *slot = ca->slot;
+       struct mantis_pci *mantis = ca->ca_priv;
+       u32 irqcfg;
+
+       slot[0].slave_cfg = 0x70773028;
+       dprintk(MANTIS_ERROR, 1, "Adapter(%d) Initializing Mantis Host Interface", mantis->num);
+
+       mutex_lock(&ca->ca_lock);
+       irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+       irqcfg = MANTIS_MASK_BRRDY      |
+                MANTIS_MASK_WRACK      |
+                MANTIS_MASK_EXTIRQ     |
+                MANTIS_MASK_WSTO       |
+                MANTIS_MASK_OTHERR     |
+                MANTIS_MASK_OVFLW;
+
+       mmwrite(irqcfg, MANTIS_GPIF_IRQCFG);
+       mutex_unlock(&ca->ca_lock);
+
+       return 0;
+}
+
+void mantis_hif_exit(struct mantis_ca *ca)
+{
+       struct mantis_pci *mantis = ca->ca_priv;
+       u32 irqcfg;
+
+       dprintk(MANTIS_ERROR, 1, "Adapter(%d) Exiting Mantis Host Interface", mantis->num);
+       mutex_lock(&ca->ca_lock);
+       irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+       irqcfg &= ~MANTIS_MASK_BRRDY;
+       mmwrite(irqcfg, MANTIS_GPIF_IRQCFG);
+       mutex_unlock(&ca->ca_lock);
+}
diff --git a/drivers/media/dvb/mantis/mantis_hif.h b/drivers/media/dvb/mantis/mantis_hif.h
new file mode 100644 (file)
index 0000000..9094f9e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_HIF_H
+#define __MANTIS_HIF_H
+
+#define MANTIS_HIF_MEMRD               1
+#define MANTIS_HIF_MEMWR               2
+#define MANTIS_HIF_IOMRD               3
+#define MANTIS_HIF_IOMWR               4
+
+#endif /* __MANTIS_HIF_H */
diff --git a/drivers/media/dvb/mantis/mantis_i2c.c b/drivers/media/dvb/mantis/mantis_i2c.c
new file mode 100644 (file)
index 0000000..7870bcf
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <asm/io.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_i2c.h"
+
+#define TRIALS                 10000
+
+static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg)
+{
+       u32 rxd, i, stat, trials;
+
+       dprintk(MANTIS_INFO, 0, "        %s:  Address=[0x%02x] <R>[ ",
+               __func__, msg->addr);
+
+       for (i = 0; i < msg->len; i++) {
+               rxd = (msg->addr << 25) | (1 << 24)
+                                       | MANTIS_I2C_RATE_3
+                                       | MANTIS_I2C_STOP
+                                       | MANTIS_I2C_PGMODE;
+
+               if (i == (msg->len - 1))
+                       rxd &= ~MANTIS_I2C_STOP;
+
+               mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
+               mmwrite(rxd, MANTIS_I2CDATA_CTL);
+
+               /* wait for xfer completion */
+               for (trials = 0; trials < TRIALS; trials++) {
+                       stat = mmread(MANTIS_INT_STAT);
+                       if (stat & MANTIS_INT_I2CDONE)
+                               break;
+               }
+
+               dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
+
+               /* wait for xfer completion */
+               for (trials = 0; trials < TRIALS; trials++) {
+                       stat = mmread(MANTIS_INT_STAT);
+                       if (stat & MANTIS_INT_I2CRACK)
+                               break;
+               }
+
+               dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
+
+               rxd = mmread(MANTIS_I2CDATA_CTL);
+               msg->buf[i] = (u8)((rxd >> 8) & 0xFF);
+               dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
+       }
+       dprintk(MANTIS_INFO, 0, "]\n");
+
+       return 0;
+}
+
+static int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg)
+{
+       int i;
+       u32 txd = 0, stat, trials;
+
+       dprintk(MANTIS_INFO, 0, "        %s: Address=[0x%02x] <W>[ ",
+               __func__, msg->addr);
+
+       for (i = 0; i < msg->len; i++) {
+               dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
+               txd = (msg->addr << 25) | (msg->buf[i] << 8)
+                                       | MANTIS_I2C_RATE_3
+                                       | MANTIS_I2C_STOP
+                                       | MANTIS_I2C_PGMODE;
+
+               if (i == (msg->len - 1))
+                       txd &= ~MANTIS_I2C_STOP;
+
+               mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
+               mmwrite(txd, MANTIS_I2CDATA_CTL);
+
+               /* wait for xfer completion */
+               for (trials = 0; trials < TRIALS; trials++) {
+                       stat = mmread(MANTIS_INT_STAT);
+                       if (stat & MANTIS_INT_I2CDONE)
+                               break;
+               }
+
+               dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
+
+               /* wait for xfer completion */
+               for (trials = 0; trials < TRIALS; trials++) {
+                       stat = mmread(MANTIS_INT_STAT);
+                       if (stat & MANTIS_INT_I2CRACK)
+                               break;
+               }
+
+               dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
+       }
+       dprintk(MANTIS_INFO, 0, "]\n");
+
+       return 0;
+}
+
+static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+{
+       int ret = 0, i = 0, trials;
+       u32 stat, data, txd;
+       struct mantis_pci *mantis;
+       struct mantis_hwconfig *config;
+
+       mantis = i2c_get_adapdata(adapter);
+       BUG_ON(!mantis);
+       config = mantis->hwconfig;
+       BUG_ON(!config);
+
+       dprintk(MANTIS_DEBUG, 1, "Messages:%d", num);
+       mutex_lock(&mantis->i2c_lock);
+
+       while (i < num) {
+               /* Byte MODE */
+               if ((config->i2c_mode & MANTIS_BYTE_MODE) &&
+                   ((i + 1) < num)                     &&
+                   (msgs[i].len < 2)                   &&
+                   (msgs[i + 1].len < 2)               &&
+                   (msgs[i + 1].flags & I2C_M_RD)) {
+
+                       dprintk(MANTIS_DEBUG, 0, "        Byte MODE:\n");
+
+                       /* Read operation */
+                       txd = msgs[i].addr << 25 | (0x1 << 24)
+                                                | (msgs[i].buf[0] << 16)
+                                                | MANTIS_I2C_RATE_3;
+
+                       mmwrite(txd, MANTIS_I2CDATA_CTL);
+                       /* wait for xfer completion */
+                       for (trials = 0; trials < TRIALS; trials++) {
+                               stat = mmread(MANTIS_INT_STAT);
+                               if (stat & MANTIS_INT_I2CDONE)
+                                       break;
+                       }
+
+                       /* check for xfer completion */
+                       if (stat & MANTIS_INT_I2CDONE) {
+                               /* check xfer was acknowledged */
+                               if (stat & MANTIS_INT_I2CRACK) {
+                                       data = mmread(MANTIS_I2CDATA_CTL);
+                                       msgs[i + 1].buf[0] = (data >> 8) & 0xff;
+                                       dprintk(MANTIS_DEBUG, 0, "        Byte <%d> RXD=0x%02x  [%02x]\n", 0x0, data, msgs[i + 1].buf[0]);
+                               } else {
+                                       /* I/O error */
+                                       dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__);
+                                       ret = -EIO;
+                                       break;
+                               }
+                       } else {
+                               /* I/O error */
+                               dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__);
+                               ret = -EIO;
+                               break;
+                       }
+                       i += 2; /* Write/Read operation in one go */
+               }
+
+               if (i < num) {
+                       if (msgs[i].flags & I2C_M_RD)
+                               ret = mantis_i2c_read(mantis, &msgs[i]);
+                       else
+                               ret = mantis_i2c_write(mantis, &msgs[i]);
+
+                       i++;
+                       if (ret < 0)
+                               goto bail_out;
+               }
+
+       }
+
+       mutex_unlock(&mantis->i2c_lock);
+
+       return num;
+
+bail_out:
+       mutex_unlock(&mantis->i2c_lock);
+       return ret;
+}
+
+static u32 mantis_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm mantis_algo = {
+       .master_xfer            = mantis_i2c_xfer,
+       .functionality          = mantis_i2c_func,
+};
+
+int __devinit mantis_i2c_init(struct mantis_pci *mantis)
+{
+       u32 intstat, intmask;
+       struct i2c_adapter *i2c_adapter = &mantis->adapter;
+       struct pci_dev *pdev            = mantis->pdev;
+
+       init_waitqueue_head(&mantis->i2c_wq);
+       mutex_init(&mantis->i2c_lock);
+       strncpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name));
+       i2c_set_adapdata(i2c_adapter, mantis);
+
+       i2c_adapter->owner      = THIS_MODULE;
+       i2c_adapter->class      = I2C_CLASS_TV_DIGITAL;
+       i2c_adapter->algo       = &mantis_algo;
+       i2c_adapter->algo_data  = NULL;
+       i2c_adapter->timeout    = 500;
+       i2c_adapter->retries    = 3;
+       i2c_adapter->dev.parent = &pdev->dev;
+
+       mantis->i2c_rc          = i2c_add_adapter(i2c_adapter);
+       if (mantis->i2c_rc < 0)
+               return mantis->i2c_rc;
+
+       dprintk(MANTIS_DEBUG, 1, "Initializing I2C ..");
+
+       intstat = mmread(MANTIS_INT_STAT);
+       intmask = mmread(MANTIS_INT_MASK);
+       mmwrite(intstat, MANTIS_INT_STAT);
+       dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
+       intmask = mmread(MANTIS_INT_MASK);
+       mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_i2c_init);
+
+int mantis_i2c_exit(struct mantis_pci *mantis)
+{
+       u32 intmask;
+
+       dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
+       intmask = mmread(MANTIS_INT_MASK);
+       mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK);
+
+       dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter");
+       return i2c_del_adapter(&mantis->adapter);
+}
+EXPORT_SYMBOL_GPL(mantis_i2c_exit);
diff --git a/drivers/media/dvb/mantis/mantis_i2c.h b/drivers/media/dvb/mantis/mantis_i2c.h
new file mode 100644 (file)
index 0000000..1342df2
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_I2C_H
+#define __MANTIS_I2C_H
+
+#define I2C_STOP               (1 <<  0)
+#define I2C_READ               (1 <<  1)
+
+extern int mantis_i2c_init(struct mantis_pci *mantis);
+extern int mantis_i2c_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_I2C_H */
diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c
new file mode 100644 (file)
index 0000000..6a9df77
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/input.h>
+#include <media/ir-common.h>
+#include <linux/pci.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_uart.h"
+
+static struct ir_scancode mantis_ir_table[] = {
+       { 0x29, KEY_POWER       },
+       { 0x28, KEY_FAVORITES   },
+       { 0x30, KEY_TEXT        },
+       { 0x17, KEY_INFO        }, /* Preview */
+       { 0x23, KEY_EPG         },
+       { 0x3b, KEY_F22         }, /* Record List */
+       { 0x3c, KEY_1           },
+       { 0x3e, KEY_2           },
+       { 0x39, KEY_3           },
+       { 0x36, KEY_4           },
+       { 0x22, KEY_5           },
+       { 0x20, KEY_6           },
+       { 0x32, KEY_7           },
+       { 0x26, KEY_8           },
+       { 0x24, KEY_9           },
+       { 0x2a, KEY_0           },
+
+       { 0x33, KEY_CANCEL      },
+       { 0x2c, KEY_BACK        },
+       { 0x15, KEY_CLEAR       },
+       { 0x3f, KEY_TAB         },
+       { 0x10, KEY_ENTER       },
+       { 0x14, KEY_UP          },
+       { 0x0d, KEY_RIGHT       },
+       { 0x0e, KEY_DOWN        },
+       { 0x11, KEY_LEFT        },
+
+       { 0x21, KEY_VOLUMEUP    },
+       { 0x35, KEY_VOLUMEDOWN  },
+       { 0x3d, KEY_CHANNELDOWN },
+       { 0x3a, KEY_CHANNELUP   },
+       { 0x2e, KEY_RECORD      },
+       { 0x2b, KEY_PLAY        },
+       { 0x13, KEY_PAUSE       },
+       { 0x25, KEY_STOP        },
+
+       { 0x1f, KEY_REWIND      },
+       { 0x2d, KEY_FASTFORWARD },
+       { 0x1e, KEY_PREVIOUS    }, /* Replay |< */
+       { 0x1d, KEY_NEXT        }, /* Skip   >| */
+
+       { 0x0b, KEY_CAMERA      }, /* Capture */
+       { 0x0f, KEY_LANGUAGE    }, /* SAP */
+       { 0x18, KEY_MODE        }, /* PIP */
+       { 0x12, KEY_ZOOM        }, /* Full screen */
+       { 0x1c, KEY_SUBTITLE    },
+       { 0x2f, KEY_MUTE        },
+       { 0x16, KEY_F20         }, /* L/R */
+       { 0x38, KEY_F21         }, /* Hibernate */
+
+       { 0x37, KEY_SWITCHVIDEOMODE }, /* A/V */
+       { 0x31, KEY_AGAIN       }, /* Recall */
+       { 0x1a, KEY_KPPLUS      }, /* Zoom+ */
+       { 0x19, KEY_KPMINUS     }, /* Zoom- */
+       { 0x27, KEY_RED         },
+       { 0x0C, KEY_GREEN       },
+       { 0x01, KEY_YELLOW      },
+       { 0x00, KEY_BLUE        },
+};
+
+struct ir_scancode_table ir_mantis = {
+       .scan = mantis_ir_table,
+       .size = ARRAY_SIZE(mantis_ir_table),
+};
+EXPORT_SYMBOL_GPL(ir_mantis);
+
+int mantis_input_init(struct mantis_pci *mantis)
+{
+       struct input_dev *rc;
+       struct ir_input_state rc_state;
+       char name[80], dev[80];
+       int err;
+
+       rc = input_allocate_device();
+       if (!rc) {
+               dprintk(MANTIS_ERROR, 1, "Input device allocate failed");
+               return -ENOMEM;
+       }
+
+       sprintf(name, "Mantis %s IR receiver", mantis->hwconfig->model_name);
+       sprintf(dev, "pci-%s/ir0", pci_name(mantis->pdev));
+
+       rc->name = name;
+       rc->phys = dev;
+
+       ir_input_init(rc, &rc_state, IR_TYPE_OTHER);
+
+       rc->id.bustype  = BUS_PCI;
+       rc->id.vendor   = mantis->vendor_id;
+       rc->id.product  = mantis->device_id;
+       rc->id.version  = 1;
+       rc->dev         = mantis->pdev->dev;
+
+       err = ir_input_register(rc, &ir_mantis);
+       if (err) {
+               dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err);
+               input_free_device(rc);
+               return -ENODEV;
+       }
+
+       mantis->rc = rc;
+
+       return 0;
+}
+
+int mantis_exit(struct mantis_pci *mantis)
+{
+       struct input_dev *rc = mantis->rc;
+
+       ir_input_unregister(rc);
+
+       return 0;
+}
diff --git a/drivers/media/dvb/mantis/mantis_ioc.c b/drivers/media/dvb/mantis/mantis_ioc.c
new file mode 100644 (file)
index 0000000..de148de
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_ioc.h"
+
+static int read_eeprom_bytes(struct mantis_pci *mantis, u8 reg, u8 *data, u8 length)
+{
+       struct i2c_adapter *adapter = &mantis->adapter;
+       int err;
+       u8 buf = reg;
+
+       struct i2c_msg msg[] = {
+               { .addr = 0x50, .flags = 0, .buf = &buf, .len = 1 },
+               { .addr = 0x50, .flags = I2C_M_RD, .buf = data, .len = length },
+       };
+
+       err = i2c_transfer(adapter, msg, 2);
+       if (err < 0) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >",
+                       err, data[0], data[1]);
+
+               return err;
+       }
+
+       return 0;
+}
+int mantis_get_mac(struct mantis_pci *mantis)
+{
+       int err;
+       u8 mac_addr[6] = {0};
+
+       err = read_eeprom_bytes(mantis, 0x08, mac_addr, 6);
+       if (err < 0) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: Mantis EEPROM read error <%d>", err);
+
+               return err;
+       }
+
+       dprintk(MANTIS_ERROR, 0,
+               "    MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+               mac_addr[0],
+               mac_addr[1],
+               mac_addr[2],
+               mac_addr[3],
+               mac_addr[4],
+               mac_addr[5]);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_get_mac);
+
+/* Turn the given bit on or off. */
+void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
+{
+       u32 cur;
+
+       dprintk(MANTIS_DEBUG, 1, "Set Bit <%d> to <%d>", bitpos, value);
+       cur = mmread(MANTIS_GPIF_ADDR);
+       if (value)
+               mantis->gpio_status = cur | (1 << bitpos);
+       else
+               mantis->gpio_status = cur & (~(1 << bitpos));
+
+       dprintk(MANTIS_DEBUG, 1, "GPIO Value <%02x>", mantis->gpio_status);
+       mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
+       mmwrite(0x00, MANTIS_GPIF_DOUT);
+}
+EXPORT_SYMBOL_GPL(gpio_set_bits);
+
+int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl)
+{
+       u32 reg;
+
+       reg = mmread(MANTIS_CONTROL);
+       switch (stream_ctl) {
+       case STREAM_TO_HIF:
+               dprintk(MANTIS_DEBUG, 1, "Set stream to HIF");
+               reg &= 0xff - MANTIS_BYPASS;
+               mmwrite(reg, MANTIS_CONTROL);
+               reg |= MANTIS_BYPASS;
+               mmwrite(reg, MANTIS_CONTROL);
+               break;
+
+       case STREAM_TO_CAM:
+               dprintk(MANTIS_DEBUG, 1, "Set stream to CAM");
+               reg |= MANTIS_BYPASS;
+               mmwrite(reg, MANTIS_CONTROL);
+               reg &= 0xff - MANTIS_BYPASS;
+               mmwrite(reg, MANTIS_CONTROL);
+               break;
+       default:
+               dprintk(MANTIS_ERROR, 1, "Unknown MODE <%02x>", stream_ctl);
+               return -1;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_stream_control);
diff --git a/drivers/media/dvb/mantis/mantis_ioc.h b/drivers/media/dvb/mantis/mantis_ioc.h
new file mode 100644 (file)
index 0000000..188fe5a
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_IOC_H
+#define __MANTIS_IOC_H
+
+#define GPIF_A00               0x00
+#define GPIF_A01               0x01
+#define GPIF_A02               0x02
+#define GPIF_A03               0x03
+#define GPIF_A04               0x04
+#define GPIF_A05               0x05
+#define GPIF_A06               0x06
+#define GPIF_A07               0x07
+#define GPIF_A08               0x08
+#define GPIF_A09               0x09
+#define GPIF_A10               0x0a
+#define GPIF_A11               0x0b
+
+#define GPIF_A12               0x0c
+#define GPIF_A13               0x0d
+#define GPIF_A14               0x0e
+
+enum mantis_stream_control {
+       STREAM_TO_HIF = 0,
+       STREAM_TO_CAM
+};
+
+extern int mantis_get_mac(struct mantis_pci *mantis);
+extern void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value);
+
+extern int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl);
+
+#endif /* __MANTIS_IOC_H */
diff --git a/drivers/media/dvb/mantis/mantis_link.h b/drivers/media/dvb/mantis/mantis_link.h
new file mode 100644 (file)
index 0000000..2a81477
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_LINK_H
+#define __MANTIS_LINK_H
+
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include "dvb_ca_en50221.h"
+
+enum mantis_sbuf_status {
+       MANTIS_SBUF_DATA_AVAIL          = 1,
+       MANTIS_SBUF_DATA_EMPTY          = 2,
+       MANTIS_SBUF_DATA_OVFLW          = 3
+};
+
+struct mantis_slot {
+       u32                             timeout;
+       u32                             slave_cfg;
+       u32                             bar;
+};
+
+/* Physical layer */
+enum mantis_slot_state {
+       MODULE_INSERTED                 = 3,
+       MODULE_XTRACTED                 = 4
+};
+
+struct mantis_ca {
+       struct mantis_slot              slot[4];
+
+       struct work_struct              hif_evm_work;
+
+       u32                             hif_event;
+       wait_queue_head_t               hif_opdone_wq;
+       wait_queue_head_t               hif_brrdyw_wq;
+       wait_queue_head_t               hif_data_wq;
+       wait_queue_head_t               hif_write_wq; /* HIF Write op */
+
+       enum mantis_sbuf_status         sbuf_status;
+
+       enum mantis_slot_state          slot_state;
+
+       void                            *ca_priv;
+
+       struct dvb_ca_en50221           en50221;
+       struct mutex                    ca_lock;
+};
+
+/* CA */
+extern void mantis_event_cam_plugin(struct mantis_ca *ca);
+extern void mantis_event_cam_unplug(struct mantis_ca *ca);
+extern int mantis_pcmcia_init(struct mantis_ca *ca);
+extern void mantis_pcmcia_exit(struct mantis_ca *ca);
+extern int mantis_evmgr_init(struct mantis_ca *ca);
+extern void mantis_evmgr_exit(struct mantis_ca *ca);
+
+/* HIF */
+extern int mantis_hif_init(struct mantis_ca *ca);
+extern void mantis_hif_exit(struct mantis_ca *ca);
+extern int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr);
+extern int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data);
+extern int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr);
+extern int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data);
+
+#endif /* __MANTIS_LINK_H */
diff --git a/drivers/media/dvb/mantis/mantis_pci.c b/drivers/media/dvb/mantis/mantis_pci.c
new file mode 100644 (file)
index 0000000..6c7534a
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+
+#include <asm/irq.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include <asm/irq.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_pci.h"
+
+#define DRIVER_NAME            "Mantis Core"
+
+int __devinit mantis_pci_init(struct mantis_pci *mantis)
+{
+       u8 revision, latency;
+       struct mantis_hwconfig *config  = mantis->hwconfig;
+       struct pci_dev *pdev            = mantis->pdev;
+       int err, ret = 0;
+
+       dprintk(MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n",
+               config->model_name,
+               config->dev_type,
+               mantis->pdev->bus->number,
+               PCI_SLOT(mantis->pdev->devfn),
+               PCI_FUNC(mantis->pdev->devfn));
+
+       err = pci_enable_device(pdev);
+       if (err != 0) {
+               ret = -ENODEV;
+               dprintk(MANTIS_ERROR, 1, "ERROR: PCI enable failed <%i>", err);
+               goto fail0;
+       }
+
+       err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (err != 0) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: Unable to obtain 32 bit DMA <%i>", err);
+               ret = -ENOMEM;
+               goto fail1;
+       }
+
+       pci_set_master(pdev);
+
+       if (!request_mem_region(pci_resource_start(pdev, 0),
+                               pci_resource_len(pdev, 0),
+                               DRIVER_NAME)) {
+
+               dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 Request failed !");
+               ret = -ENODEV;
+               goto fail1;
+       }
+
+       mantis->mmio = ioremap(pci_resource_start(pdev, 0),
+                              pci_resource_len(pdev, 0));
+
+       if (!mantis->mmio) {
+               dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 remap failed !");
+               ret = -ENODEV;
+               goto fail2;
+       }
+
+       pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
+       pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+       mantis->latency = latency;
+       mantis->revision = revision;
+
+       dprintk(MANTIS_ERROR, 0, "    Mantis Rev %d [%04x:%04x], ",
+               mantis->revision,
+               mantis->pdev->subsystem_vendor,
+               mantis->pdev->subsystem_device);
+
+       dprintk(MANTIS_ERROR, 0,
+               "irq: %d, latency: %d\n    memory: 0x%lx, mmio: 0x%p\n",
+               mantis->pdev->irq,
+               mantis->latency,
+               mantis->mantis_addr,
+               mantis->mmio);
+
+       err = request_irq(pdev->irq,
+                         config->irq_handler,
+                         IRQF_SHARED,
+                         DRIVER_NAME,
+                         mantis);
+
+       if (err != 0) {
+
+               dprintk(MANTIS_ERROR, 1, "ERROR: IRQ registration failed ! <%d>", err);
+               ret = -ENODEV;
+               goto fail3;
+       }
+
+       pci_set_drvdata(pdev, mantis);
+       return ret;
+
+       /* Error conditions */
+fail3:
+       dprintk(MANTIS_ERROR, 1, "ERROR: <%d> I/O unmap", ret);
+       if (mantis->mmio)
+               iounmap(mantis->mmio);
+
+fail2:
+       dprintk(MANTIS_ERROR, 1, "ERROR: <%d> releasing regions", ret);
+       release_mem_region(pci_resource_start(pdev, 0),
+                          pci_resource_len(pdev, 0));
+
+fail1:
+       dprintk(MANTIS_ERROR, 1, "ERROR: <%d> disabling device", ret);
+       pci_disable_device(pdev);
+
+fail0:
+       dprintk(MANTIS_ERROR, 1, "ERROR: <%d> exiting", ret);
+       pci_set_drvdata(pdev, NULL);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(mantis_pci_init);
+
+void mantis_pci_exit(struct mantis_pci *mantis)
+{
+       struct pci_dev *pdev = mantis->pdev;
+
+       dprintk(MANTIS_NOTICE, 1, " mem: 0x%p", mantis->mmio);
+       free_irq(pdev->irq, mantis);
+       if (mantis->mmio) {
+               iounmap(mantis->mmio);
+               release_mem_region(pci_resource_start(pdev, 0),
+                                  pci_resource_len(pdev, 0));
+       }
+
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+}
+EXPORT_SYMBOL_GPL(mantis_pci_exit);
+
+MODULE_DESCRIPTION("Mantis PCI DTV bridge driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/mantis_pci.h b/drivers/media/dvb/mantis/mantis_pci.h
new file mode 100644 (file)
index 0000000..65f0045
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_PCI_H
+#define __MANTIS_PCI_H
+
+extern int mantis_pci_init(struct mantis_pci *mantis);
+extern void mantis_pci_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_PCI_H */
diff --git a/drivers/media/dvb/mantis/mantis_pcmcia.c b/drivers/media/dvb/mantis/mantis_pcmcia.c
new file mode 100644 (file)
index 0000000..5cb545b
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_link.h" /* temporary due to physical layer stuff */
+#include "mantis_reg.h"
+
+/*
+ * If Slot state is already PLUG_IN event and we are called
+ * again, definitely it is jitter alone
+ */
+void mantis_event_cam_plugin(struct mantis_ca *ca)
+{
+       struct mantis_pci *mantis = ca->ca_priv;
+
+       u32 gpif_irqcfg;
+
+       if (ca->slot_state == MODULE_XTRACTED) {
+               dprintk(MANTIS_DEBUG, 1, "Event: CAM Plugged IN: Adapter(%d) Slot(0)", mantis->num);
+               udelay(50);
+               mmwrite(0xda000000, MANTIS_CARD_RESET);
+               gpif_irqcfg  = mmread(MANTIS_GPIF_IRQCFG);
+               gpif_irqcfg |= MANTIS_MASK_PLUGOUT;
+               gpif_irqcfg &= ~MANTIS_MASK_PLUGIN;
+               mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG);
+               udelay(500);
+               ca->slot_state = MODULE_INSERTED;
+       }
+       udelay(100);
+}
+
+/*
+ * If Slot state is already UN_PLUG event and we are called
+ * again, definitely it is jitter alone
+ */
+void mantis_event_cam_unplug(struct mantis_ca *ca)
+{
+       struct mantis_pci *mantis = ca->ca_priv;
+
+       u32 gpif_irqcfg;
+
+       if (ca->slot_state == MODULE_INSERTED) {
+               dprintk(MANTIS_DEBUG, 1, "Event: CAM Unplugged: Adapter(%d) Slot(0)", mantis->num);
+               udelay(50);
+               mmwrite(0x00da0000, MANTIS_CARD_RESET);
+               gpif_irqcfg  = mmread(MANTIS_GPIF_IRQCFG);
+               gpif_irqcfg |= MANTIS_MASK_PLUGIN;
+               gpif_irqcfg &= ~MANTIS_MASK_PLUGOUT;
+               mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG);
+               udelay(500);
+               ca->slot_state = MODULE_XTRACTED;
+       }
+       udelay(100);
+}
+
+int mantis_pcmcia_init(struct mantis_ca *ca)
+{
+       struct mantis_pci *mantis = ca->ca_priv;
+
+       u32 gpif_stat, card_stat;
+
+       mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_IRQ0, MANTIS_INT_MASK);
+       gpif_stat = mmread(MANTIS_GPIF_STATUS);
+       card_stat = mmread(MANTIS_GPIF_IRQCFG);
+
+       if (gpif_stat & MANTIS_GPIF_DETSTAT) {
+               dprintk(MANTIS_DEBUG, 1, "CAM found on Adapter(%d) Slot(0)", mantis->num);
+               mmwrite(card_stat | MANTIS_MASK_PLUGOUT, MANTIS_GPIF_IRQCFG);
+               ca->slot_state = MODULE_INSERTED;
+               dvb_ca_en50221_camchange_irq(&ca->en50221,
+                                            0,
+                                            DVB_CA_EN50221_CAMCHANGE_INSERTED);
+       } else {
+               dprintk(MANTIS_DEBUG, 1, "Empty Slot on Adapter(%d) Slot(0)", mantis->num);
+               mmwrite(card_stat | MANTIS_MASK_PLUGIN, MANTIS_GPIF_IRQCFG);
+               ca->slot_state = MODULE_XTRACTED;
+               dvb_ca_en50221_camchange_irq(&ca->en50221,
+                                            0,
+                                            DVB_CA_EN50221_CAMCHANGE_REMOVED);
+       }
+
+       return 0;
+}
+
+void mantis_pcmcia_exit(struct mantis_ca *ca)
+{
+       struct mantis_pci *mantis = ca->ca_priv;
+
+       mmwrite(mmread(MANTIS_GPIF_STATUS) & (~MANTIS_CARD_PLUGOUT | ~MANTIS_CARD_PLUGIN), MANTIS_GPIF_STATUS);
+       mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ0, MANTIS_INT_MASK);
+}
diff --git a/drivers/media/dvb/mantis/mantis_reg.h b/drivers/media/dvb/mantis/mantis_reg.h
new file mode 100644 (file)
index 0000000..7761f9d
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_REG_H
+#define __MANTIS_REG_H
+
+/* Interrupts */
+#define MANTIS_INT_STAT                        0x00
+#define MANTIS_INT_MASK                        0x04
+
+#define MANTIS_INT_RISCSTAT            (0x0f << 28)
+#define MANTIS_INT_RISCEN              (0x01 << 27)
+#define MANTIS_INT_I2CRACK             (0x01 << 26)
+
+/* #define MANTIS_INT_GPIF                     (0xff << 12) */
+
+#define MANTIS_INT_PCMCIA7             (0x01 << 19)
+#define MANTIS_INT_PCMCIA6             (0x01 << 18)
+#define MANTIS_INT_PCMCIA5             (0x01 << 17)
+#define MANTIS_INT_PCMCIA4             (0x01 << 16)
+#define MANTIS_INT_PCMCIA3             (0x01 << 15)
+#define MANTIS_INT_PCMCIA2             (0x01 << 14)
+#define MANTIS_INT_PCMCIA1             (0x01 << 13)
+#define MANTIS_INT_PCMCIA0             (0x01 << 12)
+#define MANTIS_INT_IRQ1                        (0x01 << 11)
+#define MANTIS_INT_IRQ0                        (0x01 << 10)
+#define MANTIS_INT_OCERR               (0x01 <<  8)
+#define MANTIS_INT_PABORT              (0x01 <<  7)
+#define MANTIS_INT_RIPERR              (0x01 <<  6)
+#define MANTIS_INT_PPERR               (0x01 <<  5)
+#define MANTIS_INT_FTRGT               (0x01 <<  3)
+#define MANTIS_INT_RISCI               (0x01 <<  1)
+#define MANTIS_INT_I2CDONE             (0x01 <<  0)
+
+/* DMA */
+#define MANTIS_DMA_CTL                 0x08
+#define MANTIS_GPIF_RD                 (0xff << 24)
+#define MANTIS_GPIF_WR                 (0xff << 16)
+#define MANTIS_CPU_DO                  (0x01 << 10)
+#define MANTIS_DRV_DO                  (0x01 <<  9)
+#define        MANTIS_I2C_RD                   (0x01 <<  7)
+#define MANTIS_I2C_WR                  (0x01 <<  6)
+#define MANTIS_DCAP_MODE               (0x01 <<  5)
+#define MANTIS_FIFO_TP_4               (0x00 <<  3)
+#define MANTIS_FIFO_TP_8               (0x01 <<  3)
+#define MANTIS_FIFO_TP_16              (0x02 <<  3)
+#define MANTIS_FIFO_EN                 (0x01 <<  2)
+#define MANTIS_DCAP_EN                 (0x01 <<  1)
+#define MANTIS_RISC_EN                 (0x01 <<  0)
+
+/* DEBUG */
+#define MANTIS_DEBUGREG                        0x0c
+#define MANTIS_DATINV                  (0x0e <<  7)
+#define MANTIS_TOP_DEBUGSEL            (0x07 <<  4)
+#define MANTIS_PCMCIA_DEBUGSEL         (0x0f <<  0)
+
+#define MANTIS_RISC_START              0x10
+#define MANTIS_RISC_PC                 0x14
+
+/* I2C */
+#define MANTIS_I2CDATA_CTL             0x18
+#define MANTIS_I2C_RATE_1              (0x00 <<  6)
+#define MANTIS_I2C_RATE_2              (0x01 <<  6)
+#define MANTIS_I2C_RATE_3              (0x02 <<  6)
+#define MANTIS_I2C_RATE_4              (0x03 <<  6)
+#define MANTIS_I2C_STOP                        (0x01 <<  5)
+#define MANTIS_I2C_PGMODE              (0x01 <<  3)
+
+/* DATA */
+#define MANTIS_CMD_DATA_R1             0x20
+#define MANTIS_CMD_DATA_3              (0xff << 24)
+#define MANTIS_CMD_DATA_2              (0xff << 16)
+#define MANTIS_CMD_DATA_1              (0xff <<  8)
+#define MANTIS_CMD_DATA_0              (0xff <<  0)
+
+#define MANTIS_CMD_DATA_R2             0x24
+#define MANTIS_CMD_DATA_7              (0xff << 24)
+#define MANTIS_CMD_DATA_6              (0xff << 16)
+#define MANTIS_CMD_DATA_5              (0xff <<  8)
+#define MANTIS_CMD_DATA_4              (0xff <<  0)
+
+#define MANTIS_CONTROL                 0x28
+#define MANTIS_DET                     (0x01 <<  7)
+#define MANTIS_DAT_CF_EN               (0x01 <<  6)
+#define MANTIS_ACS                     (0x03 <<  4)
+#define MANTIS_VCCEN                   (0x01 <<  3)
+#define MANTIS_BYPASS                  (0x01 <<  2)
+#define MANTIS_MRST                    (0x01 <<  1)
+#define MANTIS_CRST_INT                        (0x01 <<  0)
+
+#define MANTIS_GPIF_CFGSLA             0x84
+#define MANTIS_GPIF_WAITSMPL           (0x07 << 28)
+#define MANTIS_GPIF_BYTEADDRSUB                (0x01 << 25)
+#define MANTIS_GPIF_WAITPOL            (0x01 << 24)
+#define MANTIS_GPIF_NCDELAY            (0x07 << 20)
+#define MANTIS_GPIF_RW2CSDELAY         (0x07 << 16)
+#define MANTIS_GPIF_SLFTIMEDMODE       (0x01 << 15)
+#define MANTIS_GPIF_SLFTIMEDDELY       (0x7f <<  8)
+#define MANTIS_GPIF_DEVTYPE            (0x07 <<  4)
+#define MANTIS_GPIF_BIGENDIAN          (0x01 <<  3)
+#define MANTIS_GPIF_FETCHCMD           (0x03 <<  1)
+#define MANTIS_GPIF_HWORDDEV           (0x01 <<  0)
+
+#define MANTIS_GPIF_WSTOPER            0x90
+#define MANTIS_GPIF_WSTOPERWREN3       (0x01 << 31)
+#define MANTIS_GPIF_PARBOOTN           (0x01 << 29)
+#define MANTIS_GPIF_WSTOPERSLID3       (0x1f << 24)
+#define MANTIS_GPIF_WSTOPERWREN2       (0x01 << 23)
+#define MANTIS_GPIF_WSTOPERSLID2       (0x1f << 16)
+#define MANTIS_GPIF_WSTOPERWREN1       (0x01 << 15)
+#define MANTIS_GPIF_WSTOPERSLID1       (0x1f <<  8)
+#define MANTIS_GPIF_WSTOPERWREN0       (0x01 <<  7)
+#define MANTIS_GPIF_WSTOPERSLID0       (0x1f <<  0)
+
+#define MANTIS_GPIF_CS2RW              0x94
+#define MANTIS_GPIF_CS2RWWREN3         (0x01 << 31)
+#define MANTIS_GPIF_CS2RWDELY3         (0x3f << 24)
+#define MANTIS_GPIF_CS2RWWREN2         (0x01 << 23)
+#define MANTIS_GPIF_CS2RWDELY2         (0x3f << 16)
+#define MANTIS_GPIF_CS2RWWREN1         (0x01 << 15)
+#define MANTIS_GPIF_CS2RWDELY1         (0x3f <<  8)
+#define MANTIS_GPIF_CS2RWWREN0         (0x01 <<  7)
+#define MANTIS_GPIF_CS2RWDELY0         (0x3f <<  0)
+
+#define MANTIS_GPIF_IRQCFG             0x98
+#define MANTIS_GPIF_IRQPOL             (0x01 <<  8)
+#define MANTIS_MASK_WRACK              (0x01 <<  7)
+#define MANTIS_MASK_BRRDY              (0x01 <<  6)
+#define MANTIS_MASK_OVFLW              (0x01 <<  5)
+#define MANTIS_MASK_OTHERR             (0x01 <<  4)
+#define MANTIS_MASK_WSTO               (0x01 <<  3)
+#define MANTIS_MASK_EXTIRQ             (0x01 <<  2)
+#define MANTIS_MASK_PLUGIN             (0x01 <<  1)
+#define MANTIS_MASK_PLUGOUT            (0x01 <<  0)
+
+#define MANTIS_GPIF_STATUS             0x9c
+#define MANTIS_SBUF_KILLOP             (0x01 << 15)
+#define MANTIS_SBUF_OPDONE             (0x01 << 14)
+#define MANTIS_SBUF_EMPTY              (0x01 << 13)
+#define MANTIS_GPIF_DETSTAT            (0x01 <<  9)
+#define MANTIS_GPIF_INTSTAT            (0x01 <<  8)
+#define MANTIS_GPIF_WRACK              (0x01 <<  7)
+#define MANTIS_GPIF_BRRDY              (0x01 <<  6)
+#define MANTIS_SBUF_OVFLW              (0x01 <<  5)
+#define MANTIS_GPIF_OTHERR             (0x01 <<  4)
+#define MANTIS_SBUF_WSTO               (0x01 <<  3)
+#define MANTIS_GPIF_EXTIRQ             (0x01 <<  2)
+#define MANTIS_CARD_PLUGIN             (0x01 <<  1)
+#define MANTIS_CARD_PLUGOUT            (0x01 <<  0)
+
+#define MANTIS_GPIF_BRADDR             0xa0
+#define MANTIS_GPIF_PCMCIAREG          (0x01           << 27)
+#define MANTIS_GPIF_PCMCIAIOM          (0x01           << 26)
+#define MANTIS_GPIF_BR_ADDR            (0xfffffff      <<  0)
+
+#define MANTIS_GPIF_BRBYTES            0xa4
+#define MANTIS_GPIF_BRCNT              (0xfff          <<  0)
+
+#define MANTIS_PCMCIA_RESET            0xa8
+#define MANTIS_PCMCIA_RSTVAL           (0xff << 0)
+
+#define MANTIS_CARD_RESET              0xac
+
+#define MANTIS_GPIF_ADDR               0xb0
+#define MANTIS_GPIF_HIFRDWRN           (0x01           << 31)
+#define MANTIS_GPIF_PCMCIAREG          (0x01           << 27)
+#define MANTIS_GPIF_PCMCIAIOM          (0x01           << 26)
+#define MANTIS_GPIF_HIFADDR            (0xfffffff      <<  0)
+
+#define MANTIS_GPIF_DOUT               0xb4
+#define MANTIS_GPIF_HIFDOUT            (0xfffffff      <<  0)
+
+#define MANTIS_GPIF_DIN                        0xb8
+#define MANTIS_GPIF_HIFDIN             (0xfffffff      <<  0)
+
+#define MANTIS_GPIF_SPARE              0xbc
+#define MANTIS_GPIF_LOGICRD            (0xffff         << 16)
+#define MANTIS_GPIF_LOGICRW            (0xffff         <<  0)
+
+#endif /* __MANTIS_REG_H */
diff --git a/drivers/media/dvb/mantis/mantis_uart.c b/drivers/media/dvb/mantis/mantis_uart.c
new file mode 100644 (file)
index 0000000..7d2f239
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_uart.h"
+
+struct mantis_uart_params {
+       enum mantis_baud        baud_rate;
+       enum mantis_parity      parity;
+};
+
+static struct {
+       char string[7];
+} rates[5] = {
+       { "9600" },
+       { "19200" },
+       { "38400" },
+       { "57600" },
+       { "115200" }
+};
+
+static struct {
+       char string[5];
+} parity[3] = {
+       { "NONE" },
+       { "ODD" },
+       { "EVEN" }
+};
+
+#define UART_MAX_BUF                   16
+
+int mantis_uart_read(struct mantis_pci *mantis, u8 *data)
+{
+       struct mantis_hwconfig *config = mantis->hwconfig;
+       u32 stat = 0, i;
+
+       /* get data */
+       for (i = 0; i < (config->bytes + 1); i++) {
+
+               stat = mmread(MANTIS_UART_STAT);
+
+               if (stat & MANTIS_UART_RXFIFO_FULL) {
+                       dprintk(MANTIS_ERROR, 1, "RX Fifo FULL");
+               }
+               data[i] = mmread(MANTIS_UART_RXD) & 0x3f;
+
+               dprintk(MANTIS_DEBUG, 1, "Reading ... <%02x>", data[i] & 0x3f);
+
+               if (data[i] & (1 << 7)) {
+                       dprintk(MANTIS_ERROR, 1, "UART framing error");
+                       return -EINVAL;
+               }
+               if (data[i] & (1 << 6)) {
+                       dprintk(MANTIS_ERROR, 1, "UART parity error");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static void mantis_uart_work(struct work_struct *work)
+{
+       struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work);
+       struct mantis_hwconfig *config = mantis->hwconfig;
+       u8 buf[16];
+       int i;
+
+       mantis_uart_read(mantis, buf);
+
+       for (i = 0; i < (config->bytes + 1); i++)
+               dprintk(MANTIS_INFO, 1, "UART BUF:%d <%02x> ", i, buf[i]);
+
+       dprintk(MANTIS_DEBUG, 0, "\n");
+}
+
+static int mantis_uart_setup(struct mantis_pci *mantis,
+                            struct mantis_uart_params *params)
+{
+       u32 reg;
+
+       mmwrite((mmread(MANTIS_UART_CTL) | (params->parity & 0x3)), MANTIS_UART_CTL);
+
+       reg = mmread(MANTIS_UART_BAUD);
+
+       switch (params->baud_rate) {
+       case MANTIS_BAUD_9600:
+               reg |= 0xd8;
+               break;
+       case MANTIS_BAUD_19200:
+               reg |= 0x6c;
+               break;
+       case MANTIS_BAUD_38400:
+               reg |= 0x36;
+               break;
+       case MANTIS_BAUD_57600:
+               reg |= 0x23;
+               break;
+       case MANTIS_BAUD_115200:
+               reg |= 0x11;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       mmwrite(reg, MANTIS_UART_BAUD);
+
+       return 0;
+}
+
+int mantis_uart_init(struct mantis_pci *mantis)
+{
+       struct mantis_hwconfig *config = mantis->hwconfig;
+       struct mantis_uart_params params;
+
+       /* default parity: */
+       params.baud_rate = config->baud_rate;
+       params.parity = config->parity;
+       dprintk(MANTIS_INFO, 1, "Initializing UART @ %sbps parity:%s",
+               rates[params.baud_rate].string,
+               parity[params.parity].string);
+
+       init_waitqueue_head(&mantis->uart_wq);
+       spin_lock_init(&mantis->uart_lock);
+
+       INIT_WORK(&mantis->uart_work, mantis_uart_work);
+
+       /* disable interrupt */
+       mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
+
+       mantis_uart_setup(mantis, &params);
+
+       /* default 1 byte */
+       mmwrite((mmread(MANTIS_UART_BAUD) | (config->bytes << 8)), MANTIS_UART_BAUD);
+
+       /* flush buffer */
+       mmwrite((mmread(MANTIS_UART_CTL) | MANTIS_UART_RXFLUSH), MANTIS_UART_CTL);
+
+       /* enable interrupt */
+       mmwrite(mmread(MANTIS_INT_MASK) | 0x800, MANTIS_INT_MASK);
+       mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL);
+
+       schedule_work(&mantis->uart_work);
+       dprintk(MANTIS_DEBUG, 1, "UART succesfully initialized");
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_uart_init);
+
+void mantis_uart_exit(struct mantis_pci *mantis)
+{
+       /* disable interrupt */
+       mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
+}
+EXPORT_SYMBOL_GPL(mantis_uart_exit);
diff --git a/drivers/media/dvb/mantis/mantis_uart.h b/drivers/media/dvb/mantis/mantis_uart.h
new file mode 100644 (file)
index 0000000..ffb62a0
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+       Mantis PCI bridge driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_UART_H
+#define __MANTIS_UART_H
+
+#define MANTIS_UART_CTL                        0xe0
+#define MANTIS_UART_RXINT              (1 << 4)
+#define MANTIS_UART_RXFLUSH            (1 << 2)
+
+#define MANTIS_UART_RXD                        0xe8
+#define MANTIS_UART_BAUD               0xec
+
+#define MANTIS_UART_STAT               0xf0
+#define MANTIS_UART_RXFIFO_DATA                (1 << 7)
+#define MANTIS_UART_RXFIFO_EMPTY       (1 << 6)
+#define MANTIS_UART_RXFIFO_FULL                (1 << 3)
+#define MANTIS_UART_FRAME_ERR          (1 << 2)
+#define MANTIS_UART_PARITY_ERR         (1 << 1)
+#define MANTIS_UART_RXTHRESH_INT       (1 << 0)
+
+enum mantis_baud {
+       MANTIS_BAUD_9600        = 0,
+       MANTIS_BAUD_19200,
+       MANTIS_BAUD_38400,
+       MANTIS_BAUD_57600,
+       MANTIS_BAUD_115200
+};
+
+enum mantis_parity {
+       MANTIS_PARITY_NONE      = 0,
+       MANTIS_PARITY_EVEN,
+       MANTIS_PARITY_ODD,
+};
+
+struct mantis_pci;
+
+extern int mantis_uart_init(struct mantis_pci *mantis);
+extern void mantis_uart_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_UART_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.c b/drivers/media/dvb/mantis/mantis_vp1033.c
new file mode 100644 (file)
index 0000000..4a723bd
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+       Mantis VP-1033 driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "stv0299.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp1033.h"
+#include "mantis_reg.h"
+
+u8 lgtdqcs001f_inittab[] = {
+       0x01, 0x15,
+       0x02, 0x00,
+       0x03, 0x00,
+       0x04, 0x2a,
+       0x05, 0x85,
+       0x06, 0x02,
+       0x07, 0x00,
+       0x08, 0x00,
+       0x0c, 0x01,
+       0x0d, 0x81,
+       0x0e, 0x44,
+       0x0f, 0x94,
+       0x10, 0x3c,
+       0x11, 0x84,
+       0x12, 0xb9,
+       0x13, 0xb5,
+       0x14, 0x4f,
+       0x15, 0xc9,
+       0x16, 0x80,
+       0x17, 0x36,
+       0x18, 0xfb,
+       0x19, 0xcf,
+       0x1a, 0xbc,
+       0x1c, 0x2b,
+       0x1d, 0x27,
+       0x1e, 0x00,
+       0x1f, 0x0b,
+       0x20, 0xa1,
+       0x21, 0x60,
+       0x22, 0x00,
+       0x23, 0x00,
+       0x28, 0x00,
+       0x29, 0x28,
+       0x2a, 0x14,
+       0x2b, 0x0f,
+       0x2c, 0x09,
+       0x2d, 0x05,
+       0x31, 0x1f,
+       0x32, 0x19,
+       0x33, 0xfc,
+       0x34, 0x13,
+       0xff, 0xff,
+};
+
+#define MANTIS_MODEL_NAME      "VP-1033"
+#define MANTIS_DEV_TYPE                "DVB-S/DSS"
+
+int lgtdqcs001f_tuner_set(struct dvb_frontend *fe,
+                         struct dvb_frontend_parameters *params)
+{
+       struct mantis_pci *mantis       = fe->dvb->priv;
+       struct i2c_adapter *adapter     = &mantis->adapter;
+
+       u8 buf[4];
+       u32 div;
+
+
+       struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)};
+
+       div = params->frequency / 250;
+
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] =  div & 0xff;
+       buf[2] =  0x83;
+       buf[3] =  0xc0;
+
+       if (params->frequency < 1531000)
+               buf[3] |= 0x04;
+       else
+               buf[3] &= ~0x04;
+       if (i2c_transfer(adapter, &msg, 1) < 0) {
+               dprintk(MANTIS_ERROR, 1, "Write: I2C Transfer failed");
+               return -EIO;
+       }
+       msleep_interruptible(100);
+
+       return 0;
+}
+
+int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe,
+                               u32 srate, u32 ratio)
+{
+       u8 aclk = 0;
+       u8 bclk = 0;
+
+       if (srate < 1500000) {
+               aclk = 0xb7;
+               bclk = 0x47;
+       } else if (srate < 3000000) {
+               aclk = 0xb7;
+               bclk = 0x4b;
+       } else if (srate < 7000000) {
+               aclk = 0xb7;
+               bclk = 0x4f;
+       } else if (srate < 14000000) {
+               aclk = 0xb7;
+               bclk = 0x53;
+       } else if (srate < 30000000) {
+               aclk = 0xb6;
+               bclk = 0x53;
+       } else if (srate < 45000000) {
+               aclk = 0xb4;
+               bclk = 0x51;
+       }
+       stv0299_writereg(fe, 0x13, aclk);
+       stv0299_writereg(fe, 0x14, bclk);
+
+       stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+       stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff);
+       stv0299_writereg(fe, 0x21,  ratio & 0xf0);
+
+       return 0;
+}
+
+struct stv0299_config lgtdqcs001f_config = {
+       .demod_address          = 0x68,
+       .inittab                = lgtdqcs001f_inittab,
+       .mclk                   = 88000000UL,
+       .invert                 = 0,
+       .skip_reinit            = 0,
+       .volt13_op0_op1         = STV0299_VOLT13_OP0,
+       .min_delay_ms           = 100,
+       .set_symbol_rate        = lgtdqcs001f_set_symbol_rate,
+};
+
+static int vp1033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+       struct i2c_adapter *adapter     = &mantis->adapter;
+
+       int err = 0;
+
+       err = mantis_frontend_power(mantis, POWER_ON);
+       if (err == 0) {
+               mantis_frontend_soft_reset(mantis);
+               msleep(250);
+
+               dprintk(MANTIS_ERROR, 1, "Probing for STV0299 (DVB-S)");
+               fe = stv0299_attach(&lgtdqcs001f_config, adapter);
+
+               if (fe) {
+                       fe->ops.tuner_ops.set_params = lgtdqcs001f_tuner_set;
+                       dprintk(MANTIS_ERROR, 1, "found STV0299 DVB-S frontend @ 0x%02x",
+                               lgtdqcs001f_config.demod_address);
+
+                       dprintk(MANTIS_ERROR, 1, "Mantis DVB-S STV0299 frontend attach success");
+               } else {
+                       return -1;
+               }
+       } else {
+               dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+                       adapter->name,
+                       err);
+
+               return -EIO;
+       }
+       mantis->fe = fe;
+       dprintk(MANTIS_ERROR, 1, "Done!");
+
+       return 0;
+}
+
+struct mantis_hwconfig vp1033_config = {
+       .model_name             = MANTIS_MODEL_NAME,
+       .dev_type               = MANTIS_DEV_TYPE,
+       .ts_size                = MANTIS_TS_204,
+
+       .baud_rate              = MANTIS_BAUD_9600,
+       .parity                 = MANTIS_PARITY_NONE,
+       .bytes                  = 0,
+
+       .frontend_init          = vp1033_frontend_init,
+       .power                  = GPIF_A12,
+       .reset                  = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.h b/drivers/media/dvb/mantis/mantis_vp1033.h
new file mode 100644 (file)
index 0000000..7daaa1b
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+       Mantis VP-1033 driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP1033_H
+#define __MANTIS_VP1033_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_1033_DVB_S   0x0016
+
+extern struct mantis_hwconfig vp1033_config;
+
+#endif /* __MANTIS_VP1033_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp1034.c b/drivers/media/dvb/mantis/mantis_vp1034.c
new file mode 100644 (file)
index 0000000..8e6ae55
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+       Mantis VP-1034 driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mb86a16.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp1034.h"
+#include "mantis_reg.h"
+
+struct mb86a16_config vp1034_mb86a16_config = {
+       .demod_address  = 0x08,
+       .set_voltage    = vp1034_set_voltage,
+};
+
+#define MANTIS_MODEL_NAME      "VP-1034"
+#define MANTIS_DEV_TYPE                "DVB-S/DSS"
+
+int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+       struct mantis_pci *mantis = fe->dvb->priv;
+
+       switch (voltage) {
+       case SEC_VOLTAGE_13:
+               dprintk(MANTIS_ERROR, 1, "Polarization=[13V]");
+               gpio_set_bits(mantis, 13, 1);
+               gpio_set_bits(mantis, 14, 0);
+               break;
+       case SEC_VOLTAGE_18:
+               dprintk(MANTIS_ERROR, 1, "Polarization=[18V]");
+               gpio_set_bits(mantis, 13, 1);
+               gpio_set_bits(mantis, 14, 1);
+               break;
+       case SEC_VOLTAGE_OFF:
+               dprintk(MANTIS_ERROR, 1, "Frontend (dummy) POWERDOWN");
+               break;
+       default:
+               dprintk(MANTIS_ERROR, 1, "Invalid = (%d)", (u32) voltage);
+               return -EINVAL;
+       }
+       mmwrite(0x00, MANTIS_GPIF_DOUT);
+
+       return 0;
+}
+
+static int vp1034_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+       struct i2c_adapter *adapter     = &mantis->adapter;
+
+       int err = 0;
+
+       err = mantis_frontend_power(mantis, POWER_ON);
+       if (err == 0) {
+               mantis_frontend_soft_reset(mantis);
+               msleep(250);
+
+               dprintk(MANTIS_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)");
+               fe = mb86a16_attach(&vp1034_mb86a16_config, adapter);
+               if (fe) {
+                       dprintk(MANTIS_ERROR, 1,
+                       "found MB86A16 DVB-S/DSS frontend @0x%02x",
+                       vp1034_mb86a16_config.demod_address);
+
+               } else {
+                       return -1;
+               }
+       } else {
+               dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+                       adapter->name,
+                       err);
+
+               return -EIO;
+       }
+       mantis->fe = fe;
+       dprintk(MANTIS_ERROR, 1, "Done!");
+
+       return 0;
+}
+
+struct mantis_hwconfig vp1034_config = {
+       .model_name     = MANTIS_MODEL_NAME,
+       .dev_type       = MANTIS_DEV_TYPE,
+       .ts_size        = MANTIS_TS_204,
+
+       .baud_rate      = MANTIS_BAUD_9600,
+       .parity         = MANTIS_PARITY_NONE,
+       .bytes          = 0,
+
+       .frontend_init  = vp1034_frontend_init,
+       .power          = GPIF_A12,
+       .reset          = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp1034.h b/drivers/media/dvb/mantis/mantis_vp1034.h
new file mode 100644 (file)
index 0000000..323f38e
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+       Mantis VP-1034 driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP1034_H
+#define __MANTIS_VP1034_H
+
+#include "dvb_frontend.h"
+#include "mantis_common.h"
+
+
+#define MANTIS_VP_1034_DVB_S   0x0014
+
+extern struct mantis_hwconfig vp1034_config;
+extern int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+
+#endif /* __MANTIS_VP1034_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp1041.c b/drivers/media/dvb/mantis/mantis_vp1041.c
new file mode 100644 (file)
index 0000000..515346d
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+       Mantis VP-1041 driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp1041.h"
+#include "stb0899_reg.h"
+#include "stb0899_drv.h"
+#include "stb0899_cfg.h"
+#include "stb6100_cfg.h"
+#include "stb6100.h"
+#include "lnbp21.h"
+
+#define MANTIS_MODEL_NAME      "VP-1041"
+#define MANTIS_DEV_TYPE                "DSS/DVB-S/DVB-S2"
+
+static const struct stb0899_s1_reg vp1041_stb0899_s1_init_1[] = {
+
+       /* 0x0000000b, *//* SYSREG */
+       { STB0899_DEV_ID                , 0x30 },
+       { STB0899_DISCNTRL1             , 0x32 },
+       { STB0899_DISCNTRL2             , 0x80 },
+       { STB0899_DISRX_ST0             , 0x04 },
+       { STB0899_DISRX_ST1             , 0x00 },
+       { STB0899_DISPARITY             , 0x00 },
+       { STB0899_DISFIFO               , 0x00 },
+       { STB0899_DISSTATUS             , 0x20 },
+       { STB0899_DISF22                , 0x99 },
+       { STB0899_DISF22RX              , 0xa8 },
+       /* SYSREG ? */
+       { STB0899_ACRPRESC              , 0x11 },
+       { STB0899_ACRDIV1               , 0x0a },
+       { STB0899_ACRDIV2               , 0x05 },
+       { STB0899_DACR1                 , 0x00 },
+       { STB0899_DACR2                 , 0x00 },
+       { STB0899_OUTCFG                , 0x00 },
+       { STB0899_MODECFG               , 0x00 },
+       { STB0899_IRQSTATUS_3           , 0xfe },
+       { STB0899_IRQSTATUS_2           , 0x03 },
+       { STB0899_IRQSTATUS_1           , 0x7c },
+       { STB0899_IRQSTATUS_0           , 0xf4 },
+       { STB0899_IRQMSK_3              , 0xf3 },
+       { STB0899_IRQMSK_2              , 0xfc },
+       { STB0899_IRQMSK_1              , 0xff },
+       { STB0899_IRQMSK_0              , 0xff },
+       { STB0899_IRQCFG                , 0x00 },
+       { STB0899_I2CCFG                , 0x88 },
+       { STB0899_I2CRPT                , 0x58 },
+       { STB0899_IOPVALUE5             , 0x00 },
+       { STB0899_IOPVALUE4             , 0x33 },
+       { STB0899_IOPVALUE3             , 0x6d },
+       { STB0899_IOPVALUE2             , 0x90 },
+       { STB0899_IOPVALUE1             , 0x60 },
+       { STB0899_IOPVALUE0             , 0x00 },
+       { STB0899_GPIO00CFG             , 0x82 },
+       { STB0899_GPIO01CFG             , 0x82 },
+       { STB0899_GPIO02CFG             , 0x82 },
+       { STB0899_GPIO03CFG             , 0x82 },
+       { STB0899_GPIO04CFG             , 0x82 },
+       { STB0899_GPIO05CFG             , 0x82 },
+       { STB0899_GPIO06CFG             , 0x82 },
+       { STB0899_GPIO07CFG             , 0x82 },
+       { STB0899_GPIO08CFG             , 0x82 },
+       { STB0899_GPIO09CFG             , 0x82 },
+       { STB0899_GPIO10CFG             , 0x82 },
+       { STB0899_GPIO11CFG             , 0x82 },
+       { STB0899_GPIO12CFG             , 0x82 },
+       { STB0899_GPIO13CFG             , 0x82 },
+       { STB0899_GPIO14CFG             , 0x82 },
+       { STB0899_GPIO15CFG             , 0x82 },
+       { STB0899_GPIO16CFG             , 0x82 },
+       { STB0899_GPIO17CFG             , 0x82 },
+       { STB0899_GPIO18CFG             , 0x82 },
+       { STB0899_GPIO19CFG             , 0x82 },
+       { STB0899_GPIO20CFG             , 0x82 },
+       { STB0899_SDATCFG               , 0xb8 },
+       { STB0899_SCLTCFG               , 0xba },
+       { STB0899_AGCRFCFG              , 0x1c }, /* 0x11 */
+       { STB0899_GPIO22                , 0x82 }, /* AGCBB2CFG */
+       { STB0899_GPIO21                , 0x91 }, /* AGCBB1CFG */
+       { STB0899_DIRCLKCFG             , 0x82 },
+       { STB0899_CLKOUT27CFG           , 0x7e },
+       { STB0899_STDBYCFG              , 0x82 },
+       { STB0899_CS0CFG                , 0x82 },
+       { STB0899_CS1CFG                , 0x82 },
+       { STB0899_DISEQCOCFG            , 0x20 },
+       { STB0899_GPIO32CFG             , 0x82 },
+       { STB0899_GPIO33CFG             , 0x82 },
+       { STB0899_GPIO34CFG             , 0x82 },
+       { STB0899_GPIO35CFG             , 0x82 },
+       { STB0899_GPIO36CFG             , 0x82 },
+       { STB0899_GPIO37CFG             , 0x82 },
+       { STB0899_GPIO38CFG             , 0x82 },
+       { STB0899_GPIO39CFG             , 0x82 },
+       { STB0899_NCOARSE               , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
+       { STB0899_SYNTCTRL              , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
+       { STB0899_FILTCTRL              , 0x00 },
+       { STB0899_SYSCTRL               , 0x01 },
+       { STB0899_STOPCLK1              , 0x20 },
+       { STB0899_STOPCLK2              , 0x00 },
+       { STB0899_INTBUFSTATUS          , 0x00 },
+       { STB0899_INTBUFCTRL            , 0x0a },
+       { 0xffff                        , 0xff },
+};
+
+static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = {
+       { STB0899_DEMOD                 , 0x00 },
+       { STB0899_RCOMPC                , 0xc9 },
+       { STB0899_AGC1CN                , 0x01 },
+       { STB0899_AGC1REF               , 0x10 },
+       { STB0899_RTC                   , 0x23 },
+       { STB0899_TMGCFG                , 0x4e },
+       { STB0899_AGC2REF               , 0x34 },
+       { STB0899_TLSR                  , 0x84 },
+       { STB0899_CFD                   , 0xf7 },
+       { STB0899_ACLC                  , 0x87 },
+       { STB0899_BCLC                  , 0x94 },
+       { STB0899_EQON                  , 0x41 },
+       { STB0899_LDT                   , 0xf1 },
+       { STB0899_LDT2                  , 0xe3 },
+       { STB0899_EQUALREF              , 0xb4 },
+       { STB0899_TMGRAMP               , 0x10 },
+       { STB0899_TMGTHD                , 0x30 },
+       { STB0899_IDCCOMP               , 0xfd },
+       { STB0899_QDCCOMP               , 0xff },
+       { STB0899_POWERI                , 0x0c },
+       { STB0899_POWERQ                , 0x0f },
+       { STB0899_RCOMP                 , 0x6c },
+       { STB0899_AGCIQIN               , 0x80 },
+       { STB0899_AGC2I1                , 0x06 },
+       { STB0899_AGC2I2                , 0x00 },
+       { STB0899_TLIR                  , 0x30 },
+       { STB0899_RTF                   , 0x7f },
+       { STB0899_DSTATUS               , 0x00 },
+       { STB0899_LDI                   , 0xbc },
+       { STB0899_CFRM                  , 0xea },
+       { STB0899_CFRL                  , 0x31 },
+       { STB0899_NIRM                  , 0x2b },
+       { STB0899_NIRL                  , 0x80 },
+       { STB0899_ISYMB                 , 0x1d },
+       { STB0899_QSYMB                 , 0xa6 },
+       { STB0899_SFRH                  , 0x2f },
+       { STB0899_SFRM                  , 0x68 },
+       { STB0899_SFRL                  , 0x40 },
+       { STB0899_SFRUPH                , 0x2f },
+       { STB0899_SFRUPM                , 0x68 },
+       { STB0899_SFRUPL                , 0x40 },
+       { STB0899_EQUAI1                , 0x02 },
+       { STB0899_EQUAQ1                , 0xff },
+       { STB0899_EQUAI2                , 0x04 },
+       { STB0899_EQUAQ2                , 0x05 },
+       { STB0899_EQUAI3                , 0x02 },
+       { STB0899_EQUAQ3                , 0xfd },
+       { STB0899_EQUAI4                , 0x03 },
+       { STB0899_EQUAQ4                , 0x07 },
+       { STB0899_EQUAI5                , 0x08 },
+       { STB0899_EQUAQ5                , 0xf5 },
+       { STB0899_DSTATUS2              , 0x00 },
+       { STB0899_VSTATUS               , 0x00 },
+       { STB0899_VERROR                , 0x86 },
+       { STB0899_IQSWAP                , 0x2a },
+       { STB0899_ECNT1M                , 0x00 },
+       { STB0899_ECNT1L                , 0x00 },
+       { STB0899_ECNT2M                , 0x00 },
+       { STB0899_ECNT2L                , 0x00 },
+       { STB0899_ECNT3M                , 0x0a },
+       { STB0899_ECNT3L                , 0xad },
+       { STB0899_FECAUTO1              , 0x06 },
+       { STB0899_FECM                  , 0x01 },
+       { STB0899_VTH12                 , 0xb0 },
+       { STB0899_VTH23                 , 0x7a },
+       { STB0899_VTH34                 , 0x58 },
+       { STB0899_VTH56                 , 0x38 },
+       { STB0899_VTH67                 , 0x34 },
+       { STB0899_VTH78                 , 0x24 },
+       { STB0899_PRVIT                 , 0xff },
+       { STB0899_VITSYNC               , 0x19 },
+       { STB0899_RSULC                 , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+       { STB0899_TSULC                 , 0x42 },
+       { STB0899_RSLLC                 , 0x41 },
+       { STB0899_TSLPL                 , 0x12 },
+       { STB0899_TSCFGH                , 0x0c },
+       { STB0899_TSCFGM                , 0x00 },
+       { STB0899_TSCFGL                , 0x00 },
+       { STB0899_TSOUT                 , 0x69 }, /* 0x0d for CAM */
+       { STB0899_RSSYNCDEL             , 0x00 },
+       { STB0899_TSINHDELH             , 0x02 },
+       { STB0899_TSINHDELM             , 0x00 },
+       { STB0899_TSINHDELL             , 0x00 },
+       { STB0899_TSLLSTKM              , 0x1b },
+       { STB0899_TSLLSTKL              , 0xb3 },
+       { STB0899_TSULSTKM              , 0x00 },
+       { STB0899_TSULSTKL              , 0x00 },
+       { STB0899_PCKLENUL              , 0xbc },
+       { STB0899_PCKLENLL              , 0xcc },
+       { STB0899_RSPCKLEN              , 0xbd },
+       { STB0899_TSSTATUS              , 0x90 },
+       { STB0899_ERRCTRL1              , 0xb6 },
+       { STB0899_ERRCTRL2              , 0x95 },
+       { STB0899_ERRCTRL3              , 0x8d },
+       { STB0899_DMONMSK1              , 0x27 },
+       { STB0899_DMONMSK0              , 0x03 },
+       { STB0899_DEMAPVIT              , 0x5c },
+       { STB0899_PLPARM                , 0x19 },
+       { STB0899_PDELCTRL              , 0x48 },
+       { STB0899_PDELCTRL2             , 0x00 },
+       { STB0899_BBHCTRL1              , 0x00 },
+       { STB0899_BBHCTRL2              , 0x00 },
+       { STB0899_HYSTTHRESH            , 0x77 },
+       { STB0899_MATCSTM               , 0x00 },
+       { STB0899_MATCSTL               , 0x00 },
+       { STB0899_UPLCSTM               , 0x00 },
+       { STB0899_UPLCSTL               , 0x00 },
+       { STB0899_DFLCSTM               , 0x00 },
+       { STB0899_DFLCSTL               , 0x00 },
+       { STB0899_SYNCCST               , 0x00 },
+       { STB0899_SYNCDCSTM             , 0x00 },
+       { STB0899_SYNCDCSTL             , 0x00 },
+       { STB0899_ISI_ENTRY             , 0x00 },
+       { STB0899_ISI_BIT_EN            , 0x00 },
+       { STB0899_MATSTRM               , 0xf0 },
+       { STB0899_MATSTRL               , 0x02 },
+       { STB0899_UPLSTRM               , 0x45 },
+       { STB0899_UPLSTRL               , 0x60 },
+       { STB0899_DFLSTRM               , 0xe3 },
+       { STB0899_DFLSTRL               , 0x00 },
+       { STB0899_SYNCSTR               , 0x47 },
+       { STB0899_SYNCDSTRM             , 0x05 },
+       { STB0899_SYNCDSTRL             , 0x18 },
+       { STB0899_CFGPDELSTATUS1        , 0x19 },
+       { STB0899_CFGPDELSTATUS2        , 0x2b },
+       { STB0899_BBFERRORM             , 0x00 },
+       { STB0899_BBFERRORL             , 0x01 },
+       { STB0899_UPKTERRORM            , 0x00 },
+       { STB0899_UPKTERRORL            , 0x00 },
+       { 0xffff                        , 0xff },
+};
+
+struct stb0899_config vp1041_stb0899_config = {
+       .init_dev               = vp1041_stb0899_s1_init_1,
+       .init_s2_demod          = stb0899_s2_init_2,
+       .init_s1_demod          = vp1041_stb0899_s1_init_3,
+       .init_s2_fec            = stb0899_s2_init_4,
+       .init_tst               = stb0899_s1_init_5,
+
+       .demod_address          = 0x68, /*  0xd0 >> 1 */
+
+       .xtal_freq              = 27000000,
+       .inversion              = IQ_SWAP_ON, /* 1 */
+
+       .lo_clk                 = 76500000,
+       .hi_clk                 = 99000000,
+
+       .esno_ave               = STB0899_DVBS2_ESNO_AVE,
+       .esno_quant             = STB0899_DVBS2_ESNO_QUANT,
+       .avframes_coarse        = STB0899_DVBS2_AVFRAMES_COARSE,
+       .avframes_fine          = STB0899_DVBS2_AVFRAMES_FINE,
+       .miss_threshold         = STB0899_DVBS2_MISS_THRESHOLD,
+       .uwp_threshold_acq      = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+       .uwp_threshold_track    = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+       .uwp_threshold_sof      = STB0899_DVBS2_UWP_THRESHOLD_SOF,
+       .sof_search_timeout     = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+       .btr_nco_bits           = STB0899_DVBS2_BTR_NCO_BITS,
+       .btr_gain_shift_offset  = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+       .crl_nco_bits           = STB0899_DVBS2_CRL_NCO_BITS,
+       .ldpc_max_iter          = STB0899_DVBS2_LDPC_MAX_ITER,
+
+       .tuner_get_frequency    = stb6100_get_frequency,
+       .tuner_set_frequency    = stb6100_set_frequency,
+       .tuner_set_bandwidth    = stb6100_set_bandwidth,
+       .tuner_get_bandwidth    = stb6100_get_bandwidth,
+       .tuner_set_rfsiggain    = NULL,
+};
+
+struct stb6100_config vp1041_stb6100_config = {
+       .tuner_address  = 0x60,
+       .refclock       = 27000000,
+};
+
+static int vp1041_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+       struct i2c_adapter *adapter     = &mantis->adapter;
+
+       int err = 0;
+
+       err = mantis_frontend_power(mantis, POWER_ON);
+       if (err == 0) {
+               mantis_frontend_soft_reset(mantis);
+               msleep(250);
+               mantis->fe = stb0899_attach(&vp1041_stb0899_config, adapter);
+               if (mantis->fe) {
+                       dprintk(MANTIS_ERROR, 1,
+                               "found STB0899 DVB-S/DVB-S2 frontend @0x%02x",
+                               vp1041_stb0899_config.demod_address);
+
+                       if (stb6100_attach(mantis->fe, &vp1041_stb6100_config, adapter)) {
+                               if (!lnbp21_attach(mantis->fe, adapter, 0, 0))
+                                       dprintk(MANTIS_ERROR, 1, "No LNBP21 found!");
+                       }
+               } else {
+                       return -EREMOTEIO;
+               }
+       } else {
+               dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+                       adapter->name,
+                       err);
+
+               return -EIO;
+       }
+
+
+       dprintk(MANTIS_ERROR, 1, "Done!");
+
+       return 0;
+}
+
+struct mantis_hwconfig vp1041_config = {
+       .model_name     = MANTIS_MODEL_NAME,
+       .dev_type       = MANTIS_DEV_TYPE,
+       .ts_size        = MANTIS_TS_188,
+
+       .baud_rate      = MANTIS_BAUD_9600,
+       .parity         = MANTIS_PARITY_NONE,
+       .bytes          = 0,
+
+       .frontend_init  = vp1041_frontend_init,
+       .power          = GPIF_A12,
+       .reset          = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp1041.h b/drivers/media/dvb/mantis/mantis_vp1041.h
new file mode 100644 (file)
index 0000000..1ae5b3d
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+       Mantis VP-1041 driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP1041_H
+#define __MANTIS_VP1041_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_1041_DVB_S2  0x0031
+#define SKYSTAR_HD2_10         0x0001
+#define SKYSTAR_HD2_20         0x0003
+#define CINERGY_S2_PCI_HD      0x1179
+
+extern struct mantis_hwconfig vp1041_config;
+
+#endif /* __MANTIS_VP1041_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp2033.c b/drivers/media/dvb/mantis/mantis_vp2033.c
new file mode 100644 (file)
index 0000000..10ce817
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+       Mantis VP-2033 driver
+
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       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; either version 2 of the License, or
+       (at your option) any later version.
+
+       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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "tda1002x.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp2033.h"
+
+#define MANTIS_MODEL_NAME      "VP-2033"
+#define MANTIS_DEV_TYPE                "DVB-C"
+
+struct tda1002x_config vp2033_tda1002x_cu1216_config = {
+       .demod_address = 0x18 >> 1,
+       .invert = 1,
+};
+
+struct tda10023_config vp2033_tda10023_cu1216_config = {
+       .demod_address = 0x18 >> 1,
+       .invert = 1,
+};
+
+static u8 read_pwm(struct mantis_pci *mantis)
+{
+       struct i2c_adapter *adapter = &mantis->adapter;
+
+       u8 b = 0xff;
+       u8 pwm;
+       struct i2c_msg msg[] = {
+               {.addr = 0x50, .flags = 0, .buf = &b, .len = 1},
+               {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1}
+       };
+
+       if ((i2c_transfer(adapter, msg, 2) != 2)
+           || (pwm == 0xff))
+               pwm = 0x48;
+
+       return pwm;
+}
+
+static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       struct mantis_pci *mantis = fe->dvb->priv;
+       struct i2c_adapter *adapter = &mantis->adapter;
+
+       u8 buf[6];
+       struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)};
+       int i;
+
+#define CU1216_IF 36125000
+#define TUNER_MUL 62500
+
+       u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = div & 0xff;
+       buf[2] = 0xce;
+       buf[3] = (params->frequency < 150000000 ? 0x01 :
+                 params->frequency < 445000000 ? 0x02 : 0x04);
+       buf[4] = 0xde;
+       buf[5] = 0x20;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+
+       if (i2c_transfer(adapter, &msg, 1) != 1)
+               return -EIO;
+
+       /* wait for the pll lock */
+       msg.flags = I2C_M_RD;
+       msg.len = 1;
+       for (i = 0; i < 20; i++) {
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 1);
+
+               if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40))
+                       break;
+
+               msleep(10);
+       }
+
+       /* switch the charge pump to the lower current */
+       msg.flags = 0;
+       msg.len = 2;
+       msg.buf = &buf[2];
+       buf[2] &= ~0x40;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+
+       if (i2c_transfer(adapter, &msg, 1) != 1)
+               return -EIO;
+
+       return 0;
+}
+
+static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+       struct i2c_adapter *adapter = &mantis->adapter;
+
+       int err = 0;
+
+       err = mantis_frontend_power(mantis, POWER_ON);
+       if (err == 0) {
+               mantis_frontend_soft_reset(mantis);
+               msleep(250);
+
+               dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)");
+               fe = tda10021_attach(&vp2033_tda1002x_cu1216_config,
+                                    adapter,
+                                    read_pwm(mantis));
+
+               if (fe) {
+                       dprintk(MANTIS_ERROR, 1,
+                               "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x",
+                               vp2033_tda1002x_cu1216_config.demod_address);
+               } else {
+                       fe = tda10023_attach(&vp2033_tda10023_cu1216_config,
+                                            adapter,
+                                            read_pwm(mantis));
+
+                       if (fe) {
+                               dprintk(MANTIS_ERROR, 1,
+                                       "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x",
+                                       vp2033_tda1002x_cu1216_config.demod_address);
+                       }
+               }
+
+               if (fe) {
+                       fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set;
+                       dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success");
+               } else {
+                       return -1;
+               }
+       } else {
+               dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+                       adapter->name,
+                       err);
+