Files
LibreELEC.tv/packages/linux/patches/3.14/linux-950-saa716x_PCIe_interface_chipset.patch
2014-03-31 15:38:36 +02:00

13032 lines
356 KiB
Diff

diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index b85f88c..238b2ed 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -22,4 +22,5 @@ config CYPRESS_FIRMWARE
source "drivers/media/common/b2c2/Kconfig"
source "drivers/media/common/saa7146/Kconfig"
+source "drivers/media/common/saa716x/Kconfig"
source "drivers/media/common/siano/Kconfig"
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index d208de3..b3c373d 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1,4 +1,4 @@
-obj-y += b2c2/ saa7146/ siano/
+obj-y += b2c2/ saa7146/ saa716x/ siano/
obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
diff --git a/drivers/media/common/saa716x/Kconfig b/drivers/media/common/saa716x/Kconfig
new file mode 100644
index 0000000..e667a58
--- /dev/null
+++ b/drivers/media/common/saa716x/Kconfig
@@ -0,0 +1,67 @@
+menuconfig SAA716X_SUPPORT
+ bool "Support for SAA716x family from NXP/Philips"
+ depends on PCI && I2C
+ help
+ support for saa716x
+
+if SAA716X_SUPPORT
+config SAA716X_CORE
+ tristate "SAA7160/1/2 PCI Express bridge based devices"
+ depends on PCI && I2C
+
+ help
+ Support for PCI cards based on the SAA7160/1/2 PCI Express bridge.
+
+ Say Y if you own such a device and want to use it.
+
+config DVB_SAA716X_BUDGET
+ tristate "SAA7160/1/2 based Budget PCIe cards (DVB only)"
+ depends on SAA716X_CORE && DVB_CORE
+ select DVB_DS3000 if !DVB_FE_CUSTOMISE
+ select DVB_DS3103 if !DVB_FE_CUSTOMISE
+ select DVB_TS2022 if !DVB_FE_CUSTOMISE
+
+ help
+ Support for the SAA7160/1/2 based Budget PCIe DVB cards
+ Currently supported devices are:
+
+ * KNC1 Dual S2 (DVB-S, DVB-S/S2)
+ * Twinhan/Azurewave VP-1028 (DVB-S)
+ * Twinhan/Azurewave VP-3071 (DVB-T x2)
+ * Twinhan/Azurewave VP-6002 (DVB-S)
+
+ Say Y if you own such a device and want to use it.
+
+config DVB_SAA716X_HYBRID
+ tristate "SAA7160/1/2 based Hybrid PCIe cards (DVB + Analog)"
+ depends on SAA716X_CORE && DVB_CORE
+
+ help
+ Support for the SAA7160/1/2 based Hybrid PCIe DVB cards
+ Currently supported devices are:
+
+ * Avermedia H-788 (DVB-T)
+ * Avermedia HC-82 (DVB-T)
+ * NXP Reference (Atlantis) (DVB-T x2)
+ * NXP Reference (Nemo) (DVB-T)
+ * Twinhan/Azurewave VP-6090 (DVB-S x2, DVB-T x2)
+
+ Say Y if you own such a device and want to use it.
+
+#config DVB_SAA716X_FF
+# tristate "SAA7160/1/2 based Full Fledged PCIe cards"
+# depends on SAA716X_CORE && DVB_CORE
+# depends on INPUT # IR
+# default n
+
+# help
+# Support for the SAA7160/1/2 based Full fledged PCIe DVB cards
+# These cards do feature a hardware MPEG decoder and other
+# peripherals. Also known as Premium cards.
+# Currently supported devices are:
+
+# * Technotrend S2 6400 Dual S2 HD (DVB-S/S2 x2)
+
+# Say Y if you own such a device and want to use it.
+
+endif # SAA716X_SUPPORT
diff --git a/drivers/media/common/saa716x/Makefile b/drivers/media/common/saa716x/Makefile
new file mode 100644
index 0000000..c86f224
--- /dev/null
+++ b/drivers/media/common/saa716x/Makefile
@@ -0,0 +1,26 @@
+saa716x_core-objs := saa716x_pci.o \
+ saa716x_i2c.o \
+ saa716x_cgu.o \
+ saa716x_msi.o \
+ saa716x_dma.o \
+ saa716x_vip.o \
+ saa716x_aip.o \
+ saa716x_phi.o \
+ saa716x_boot.o \
+ saa716x_fgpi.o \
+ saa716x_adap.o \
+ saa716x_gpio.o \
+ saa716x_greg.o \
+ saa716x_rom.o \
+ saa716x_spi.o
+
+#saa716x_ff-objs := saa716x_ff_main.o \
+# saa716x_ff_cmd.o \
+# saa716x_ff_ir.o
+
+obj-$(CONFIG_SAA716X_CORE) += saa716x_core.o
+obj-$(CONFIG_DVB_SAA716X_BUDGET) += saa716x_budget.o
+obj-$(CONFIG_DVB_SAA716X_HYBRID) += saa716x_hybrid.o
+#obj-$(CONFIG_DVB_SAA716X_FF) += saa716x_ff.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/ -Idrivers/media/tuners/
diff --git a/drivers/media/common/saa716x/saa716x_adap.c b/drivers/media/common/saa716x/saa716x_adap.c
new file mode 100644
index 0000000..6d7346c
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_adap.c
@@ -0,0 +1,274 @@
+#include <linux/bitops.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
+#include "saa716x_mod.h"
+#include "saa716x_spi.h"
+#include "saa716x_adap.h"
+#include "saa716x_i2c.h"
+#include "saa716x_gpio.h"
+#include "saa716x_priv.h"
+#include "saa716x_budget.h"
+
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+
+void saa716x_dma_start(struct saa716x_dev *saa716x, u8 adapter)
+{
+ struct fgpi_stream_params params;
+
+ dprintk(SAA716x_DEBUG, 1, "SAA716x Start DMA engine for Adapter:%d", adapter);
+
+ params.bits = 8;
+ params.samples = 188;
+ params.lines = 348;
+ params.pitch = 188;
+ params.offset = 0;
+ params.page_tables = 0;
+ params.stream_type = FGPI_TRANSPORT_STREAM;
+ params.stream_flags = 0;
+
+ saa716x_fgpi_start(saa716x, saa716x->config->adap_config[adapter].ts_port, &params);
+}
+
+void saa716x_dma_stop(struct saa716x_dev *saa716x, u8 adapter)
+{
+ dprintk(SAA716x_DEBUG, 1, "SAA716x Stop DMA engine for Adapter:%d", adapter);
+
+ saa716x_fgpi_stop(saa716x, saa716x->config->adap_config[adapter].ts_port);
+}
+
+static int saa716x_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct saa716x_adapter *saa716x_adap = dvbdmx->priv;
+ struct saa716x_dev *saa716x = saa716x_adap->saa716x;
+
+ dprintk(SAA716x_DEBUG, 1, "SAA716x DVB Start feed");
+ if (!dvbdmx->dmx.frontend) {
+ dprintk(SAA716x_DEBUG, 1, "no frontend ?");
+ return -EINVAL;
+ }
+ saa716x_adap->feeds++;
+ dprintk(SAA716x_DEBUG, 1, "SAA716x start feed, feeds=%d",
+ saa716x_adap->feeds);
+
+ if (saa716x_adap->feeds == 1) {
+ dprintk(SAA716x_DEBUG, 1, "SAA716x start feed & dma");
+ saa716x_dma_start(saa716x, saa716x_adap->count);
+ }
+
+ return saa716x_adap->feeds;
+}
+
+static int saa716x_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct saa716x_adapter *saa716x_adap = dvbdmx->priv;
+ struct saa716x_dev *saa716x = saa716x_adap->saa716x;
+
+ dprintk(SAA716x_DEBUG, 1, "SAA716x DVB Stop feed");
+ if (!dvbdmx->dmx.frontend) {
+ dprintk(SAA716x_DEBUG, 1, "no frontend ?");
+ return -EINVAL;
+ }
+ saa716x_adap->feeds--;
+ if (saa716x_adap->feeds == 0) {
+ dprintk(SAA716x_DEBUG, 1, "saa716x stop feed and dma");
+ saa716x_dma_stop(saa716x, saa716x_adap->count);
+ }
+
+ return 0;
+}
+
+int saa716x_dvb_init(struct saa716x_dev *saa716x)
+{
+ struct saa716x_adapter *saa716x_adap = saa716x->saa716x_adap;
+ struct saa716x_config *config = saa716x->config;
+ int result, i;
+
+ mutex_init(&saa716x->adap_lock);
+
+ for (i = 0; i < config->adapters; i++) {
+
+ dprintk(SAA716x_DEBUG, 1, "dvb_register_adapter");
+ if (dvb_register_adapter(&saa716x_adap->dvb_adapter,
+ "SAA716x dvb adapter",
+ THIS_MODULE,
+ &saa716x->pdev->dev,
+ adapter_nr) < 0) {
+
+ dprintk(SAA716x_ERROR, 1, "Error registering adapter");
+ return -ENODEV;
+ }
+
+ saa716x_adap->count = i;
+
+ saa716x_adap->dvb_adapter.priv = saa716x_adap;
+ saa716x_adap->demux.dmx.capabilities = DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+
+ saa716x_adap->demux.priv = saa716x_adap;
+ saa716x_adap->demux.filternum = 256;
+ saa716x_adap->demux.feednum = 256;
+ saa716x_adap->demux.start_feed = saa716x_dvb_start_feed;
+ saa716x_adap->demux.stop_feed = saa716x_dvb_stop_feed;
+ saa716x_adap->demux.write_to_decoder = NULL;
+ switch (saa716x->pdev->subsystem_device) {
+ case TEVII_S472: {
+ struct saa716x_i2c *i2c = saa716x->i2c;
+ struct i2c_adapter *adapter = &i2c[SAA716x_I2C_BUS_B].i2c_adapter;
+ u8 mac[6];
+ u8 b0[] = { 0, 9 };
+ struct i2c_msg msg[] = {
+ {
+ .addr = 0x50,
+ .flags = 0,
+ .buf = b0,
+ .len = 2
+ }, {
+ .addr = 0x50,
+ .flags = I2C_M_RD,
+ .buf = mac,
+ .len = 6
+ }
+ };
+
+ i2c_transfer(adapter, msg, 2);
+ dprintk(SAA716x_INFO, 1, "TeVii S472 MAC= %pM\n", mac);
+ memcpy(saa716x_adap->dvb_adapter.proposed_mac, mac, 6);
+ }
+ }
+
+ dprintk(SAA716x_DEBUG, 1, "dvb_dmx_init");
+ if ((result = dvb_dmx_init(&saa716x_adap->demux)) < 0) {
+ dprintk(SAA716x_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err0;
+ }
+
+ saa716x_adap->dmxdev.filternum = 256;
+ saa716x_adap->dmxdev.demux = &saa716x_adap->demux.dmx;
+ saa716x_adap->dmxdev.capabilities = 0;
+
+ dprintk(SAA716x_DEBUG, 1, "dvb_dmxdev_init");
+ if ((result = dvb_dmxdev_init(&saa716x_adap->dmxdev,
+ &saa716x_adap->dvb_adapter)) < 0) {
+
+ dprintk(SAA716x_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result);
+ goto err1;
+ }
+
+ saa716x_adap->fe_hw.source = DMX_FRONTEND_0;
+
+ if ((result = saa716x_adap->demux.dmx.add_frontend(&saa716x_adap->demux.dmx,
+ &saa716x_adap->fe_hw)) < 0) {
+
+ dprintk(SAA716x_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err2;
+ }
+
+ saa716x_adap->fe_mem.source = DMX_MEMORY_FE;
+
+ if ((result = saa716x_adap->demux.dmx.add_frontend(&saa716x_adap->demux.dmx,
+ &saa716x_adap->fe_mem)) < 0) {
+ dprintk(SAA716x_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err3;
+ }
+
+ if ((result = saa716x_adap->demux.dmx.connect_frontend(&saa716x_adap->demux.dmx,
+ &saa716x_adap->fe_hw)) < 0) {
+
+ dprintk(SAA716x_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err4;
+ }
+
+ dvb_net_init(&saa716x_adap->dvb_adapter, &saa716x_adap->dvb_net, &saa716x_adap->demux.dmx);
+// tasklet_init(&saa716x_adap->tasklet, saa716x_dma_xfer, (unsigned long) saa716x);
+ dprintk(SAA716x_DEBUG, 1, "Frontend Init");
+ saa716x_adap->saa716x = saa716x;
+
+ if (config->frontend_attach) {
+ result = config->frontend_attach(saa716x_adap, i);
+ if (result < 0)
+ dprintk(SAA716x_ERROR, 1, "SAA716x frontend attach failed");
+
+ if (saa716x_adap->fe == NULL) {
+ dprintk(SAA716x_ERROR, 1, "A frontend driver was not found for [%04x:%04x] subsystem [%04x:%04x]\n",
+ saa716x->pdev->vendor,
+ saa716x->pdev->device,
+ saa716x->pdev->subsystem_vendor,
+ saa716x->pdev->subsystem_device);
+ } else {
+ result = dvb_register_frontend(&saa716x_adap->dvb_adapter, saa716x_adap->fe);
+ if (result < 0) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x register frontend failed");
+ goto err6;
+ }
+ }
+
+ } else {
+ dprintk(SAA716x_ERROR, 1, "Frontend attach = NULL");
+ }
+
+ saa716x_fgpi_init(saa716x, config->adap_config[i].ts_port,
+ config->adap_config[i].worker);
+
+ saa716x_adap++;
+ }
+
+
+ return 0;
+
+ /* Error conditions */
+err6:
+ dvb_frontend_detach(saa716x_adap->fe);
+err4:
+ saa716x_adap->demux.dmx.remove_frontend(&saa716x_adap->demux.dmx, &saa716x_adap->fe_mem);
+err3:
+ saa716x_adap->demux.dmx.remove_frontend(&saa716x_adap->demux.dmx, &saa716x_adap->fe_hw);
+err2:
+ dvb_dmxdev_release(&saa716x_adap->dmxdev);
+err1:
+ dvb_dmx_release(&saa716x_adap->demux);
+err0:
+ dvb_unregister_adapter(&saa716x_adap->dvb_adapter);
+
+ return result;
+}
+EXPORT_SYMBOL(saa716x_dvb_init);
+
+void saa716x_dvb_exit(struct saa716x_dev *saa716x)
+{
+ struct saa716x_adapter *saa716x_adap = saa716x->saa716x_adap;
+ int i;
+
+ for (i = 0; i < saa716x->config->adapters; i++) {
+
+ saa716x_fgpi_exit(saa716x, saa716x->config->adap_config[i].ts_port);
+
+ if (saa716x_adap->fe) {
+ dvb_unregister_frontend(saa716x_adap->fe);
+ dvb_frontend_detach(saa716x_adap->fe);
+ }
+
+// tasklet_kill(&saa716x->tasklet);
+ dvb_net_release(&saa716x_adap->dvb_net);
+ saa716x_adap->demux.dmx.remove_frontend(&saa716x_adap->demux.dmx, &saa716x_adap->fe_mem);
+ saa716x_adap->demux.dmx.remove_frontend(&saa716x_adap->demux.dmx, &saa716x_adap->fe_hw);
+ dvb_dmxdev_release(&saa716x_adap->dmxdev);
+ dvb_dmx_release(&saa716x_adap->demux);
+
+ dprintk(SAA716x_DEBUG, 1, "dvb_unregister_adapter");
+ dvb_unregister_adapter(&saa716x_adap->dvb_adapter);
+
+ saa716x_adap++;
+ }
+
+ return;
+}
+EXPORT_SYMBOL(saa716x_dvb_exit);
diff --git a/drivers/media/common/saa716x/saa716x_adap.h b/drivers/media/common/saa716x/saa716x_adap.h
new file mode 100644
index 0000000..7822e36
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_adap.h
@@ -0,0 +1,9 @@
+#ifndef __SAA716x_ADAP_H
+#define __SAA716x_ADAP_H
+
+struct saa716x_dev;
+
+extern int saa716x_dvb_init(struct saa716x_dev *saa716x);
+extern void saa716x_dvb_exit(struct saa716x_dev *saa716x);
+
+#endif /* __SAA716x_ADAP_H */
diff --git a/drivers/media/common/saa716x/saa716x_aip.c b/drivers/media/common/saa716x/saa716x_aip.c
new file mode 100644
index 0000000..3bdb265
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_aip.c
@@ -0,0 +1,20 @@
+#include <linux/kernel.h>
+
+#include "saa716x_mod.h"
+#include "saa716x_aip_reg.h"
+#include "saa716x_spi.h"
+#include "saa716x_aip.h"
+#include "saa716x_priv.h"
+
+int saa716x_aip_status(struct saa716x_dev *saa716x, u32 dev)
+{
+ return SAA716x_EPRD(dev, AI_CTL) == 0 ? 0 : -1;
+}
+EXPORT_SYMBOL_GPL(saa716x_aip_status);
+
+void saa716x_aip_disable(struct saa716x_dev *saa716x)
+{
+ SAA716x_EPWR(AI0, AI_CTL, 0x00);
+ SAA716x_EPWR(AI1, AI_CTL, 0x00);
+}
+EXPORT_SYMBOL_GPL(saa716x_aip_disable);
diff --git a/drivers/media/common/saa716x/saa716x_aip.h b/drivers/media/common/saa716x/saa716x_aip.h
new file mode 100644
index 0000000..36277b7
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_aip.h
@@ -0,0 +1,9 @@
+#ifndef __SAA716x_AIP_H
+#define __SAA716x_AIP_H
+
+struct saa716x_dev;
+
+extern int saa716x_aip_status(struct saa716x_dev *saa716x, u32 dev);
+extern void saa716x_aip_disable(struct saa716x_dev *saa716x);
+
+#endif /* __SAA716x_AIP_H */
diff --git a/drivers/media/common/saa716x/saa716x_aip_reg.h b/drivers/media/common/saa716x/saa716x_aip_reg.h
new file mode 100644
index 0000000..3e0893a
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_aip_reg.h
@@ -0,0 +1,62 @@
+#ifndef __SAA716x_AIP_REG_H
+#define __SAA716x_AIP_REG_H
+
+/* -------------- AI Registers ---------------- */
+
+#define AI_STATUS 0x000
+#define AI_BUF1_ACTIVE (0x00000001 << 4)
+#define AI_OVERRUN (0x00000001 << 3)
+#define AI_HBE (0x00000001 << 2)
+#define AI_BUF2_FULL (0x00000001 << 1)
+#define AI_BUF1_FULL (0x00000001 << 0)
+
+#define AI_CTL 0x004
+#define AI_RESET (0x00000001 << 31)
+#define AI_CAP_ENABLE (0x00000001 << 30)
+#define AI_CAP_MODE (0x00000003 << 28)
+#define AI_SIGN_CONVERT (0x00000001 << 27)
+#define AI_EARLYMODE (0x00000001 << 26)
+#define AI_DIAGMODE (0x00000001 << 25)
+#define AI_RAWMODE (0x00000001 << 24)
+#define AI_OVR_INTEN (0x00000001 << 7)
+#define AI_HBE_INTEN (0x00000001 << 6)
+#define AI_BUF2_INTEN (0x00000001 << 5)
+#define AI_BUF1_INTEN (0x00000001 << 4)
+#define AI_ACK_OVR (0x00000001 << 3)
+#define AI_ACK_HBE (0x00000001 << 2)
+#define AI_ACK2 (0x00000001 << 1)
+#define AI_ACK1 (0x00000001 << 0)
+
+#define AI_SERIAL 0x008
+#define AI_SER_MASTER (0x00000001 << 31)
+#define AI_DATAMODE (0x00000001 << 30)
+#define AI_FRAMEMODE (0x00000003 << 28)
+#define AI_CLOCK_EDGE (0x00000001 << 27)
+#define AI_SSPOS4 (0x00000001 << 19)
+#define AI_NR_CHAN (0x00000003 << 17)
+#define AI_WSDIV (0x000001ff << 8)
+#define AI_SCKDIV (0x000000ff << 0)
+
+#define AI_FRAMING 0x00c
+#define AI_VALIDPOS (0x000001ff << 22)
+#define AI_LEFTPOS (0x000001ff << 13)
+#define AI_RIGHTPOS (0x000001ff << 4)
+#define AI_SSPOS_3_0 (0x0000000f << 0)
+
+#define AI_BASE1 0x014
+#define AI_BASE2 0x018
+#define AI_BASE (0x03ffffff << 6)
+
+#define AI_SIZE 0x01c
+#define AI_SAMPLE_SIZE (0x03ffffff << 6)
+
+#define AI_INT_ACK 0x020
+#define AI_ACK_OVR (0x00000001 << 3)
+#define AI_ACK_HBE (0x00000001 << 2)
+#define AI_ACK2 (0x00000001 << 1)
+#define AI_ACK1 (0x00000001 << 0)
+
+#define AI_PWR_DOWN 0xff4
+#define AI_PWR_DWN (0x00000001 << 0)
+
+#endif /* __SAA716x_AIP_REG_H */
diff --git a/drivers/media/common/saa716x/saa716x_boot.c b/drivers/media/common/saa716x/saa716x_boot.c
new file mode 100644
index 0000000..21e59d0
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_boot.c
@@ -0,0 +1,319 @@
+#include <linux/delay.h>
+
+#include "saa716x_mod.h"
+
+#include "saa716x_greg_reg.h"
+#include "saa716x_cgu_reg.h"
+#include "saa716x_vip_reg.h"
+#include "saa716x_aip_reg.h"
+#include "saa716x_msi_reg.h"
+#include "saa716x_dma_reg.h"
+#include "saa716x_gpio_reg.h"
+#include "saa716x_fgpi_reg.h"
+#include "saa716x_dcs_reg.h"
+
+#include "saa716x_boot.h"
+#include "saa716x_spi.h"
+#include "saa716x_priv.h"
+
+static int saa716x_ext_boot(struct saa716x_dev *saa716x)
+{
+ /* Write GREG boot_ready to 0
+ * DW_0 = 0x0001_2018
+ * DW_1 = 0x0000_0000
+ */
+ SAA716x_EPWR(GREG, GREG_RSTU_CTRL, 0x00000000);
+
+ /* Clear VI0 interrupt
+ * DW_2 = 0x0000_0fe8
+ * DW_3 = 0x0000_03ff
+ */
+ SAA716x_EPWR(VI0, INT_CLR_STATUS, 0x000003ff);
+
+ /* Clear VI1 interrupt
+ * DW_4 = 0x0000_1fe8
+ * DW_5 = 0x0000_03ff
+ */
+ SAA716x_EPWR(VI1, INT_CLR_STATUS, 0x000003ff);
+
+ /* CLear FGPI0 interrupt
+ * DW_6 = 0x0000_2fe8
+ * DW_7 = 0x0000_007f
+ */
+ SAA716x_EPWR(FGPI0, INT_CLR_STATUS, 0x0000007f);
+
+ /* Clear FGPI1 interrupt
+ * DW_8 = 0x0000_3fe8
+ * DW_9 = 0x0000_007f
+ */
+ SAA716x_EPWR(FGPI1, INT_CLR_STATUS, 0x0000007f);
+
+ /* Clear FGPI2 interrupt
+ * DW_10 = 0x0000_4fe8
+ * DW_11 = 0x0000_007f
+ */
+ SAA716x_EPWR(FGPI2, INT_CLR_STATUS, 0x0000007f);
+
+ /* Clear FGPI3 interrupt
+ * DW_12 = 0x0000_5fe8
+ * DW_13 = 0x0000_007f
+ */
+ SAA716x_EPWR(FGPI3, INT_CLR_STATUS, 0x0000007f);
+
+ /* Clear AI0 interrupt
+ * DW_14 = 0x0000_6020
+ * DW_15 = 0x0000_000f
+ */
+ SAA716x_EPWR(AI0, AI_INT_ACK, 0x0000000f);
+
+ /* Clear AI1 interrupt
+ * DW_16 = 0x0000_7020
+ * DW_17 = 0x0000_200f
+ */
+ SAA716x_EPWR(AI1, AI_INT_ACK, 0x0000000f);
+
+ /* Set GREG boot_ready bit to 1
+ * DW_18 = 0x0001_2018
+ * DW_19 = 0x0000_2000
+ */
+ SAA716x_EPWR(GREG, GREG_RSTU_CTRL, 0x00002000);
+#if 0
+ /* End of Boot script command
+ * DW_20 = 0x0000_0006
+ * Where to write this value ??
+ * This seems very odd an address to trigger the
+ * Boot Control State Machine !
+ */
+ SAA716x_EPWR(VI0, 0x00000006, 0xffffffff);
+#endif
+ return 0;
+}
+
+/* Internal Bootscript configuration */
+static void saa716x_int_boot(struct saa716x_dev *saa716x)
+{
+ /* #1 Configure PCI COnfig space
+ * GREG_JETSTR_CONFIG_0
+ */
+ SAA716x_EPWR(GREG, GREG_SUBSYS_CONFIG, saa716x->pdev->subsystem_vendor);
+
+ /* GREG_JETSTR_CONFIG_1
+ * pmcsr_scale:7 = 0x00
+ * pmcsr_scale:6 = 0x00
+ * pmcsr_scale:5 = 0x00
+ * pmcsr_scale:4 = 0x00
+ * pmcsr_scale:3 = 0x00
+ * pmcsr_scale:2 = 0x00
+ * pmcsr_scale:1 = 0x00
+ * pmcsr_scale:0 = 0x00
+ * BAR mask = 20 bit
+ * BAR prefetch = no
+ * MSI capable = 32 messages
+ */
+ SAA716x_EPWR(GREG, GREG_MSI_BAR_PMCSR, 0x00001005);
+
+ /* GREG_JETSTR_CONFIG_2
+ * pmcsr_data:3 = 0x0
+ * pmcsr_data:2 = 0x0
+ * pmcsr_data:1 = 0x0
+ * pmcsr_data:0 = 0x0
+ */
+ SAA716x_EPWR(GREG, GREG_PMCSR_DATA_1, 0x00000000);
+
+ /* GREG_JETSTR_CONFIG_3
+ * pmcsr_data:7 = 0x0
+ * pmcsr_data:6 = 0x0
+ * pmcsr_data:5 = 0x0
+ * pmcsr_data:4 = 0x0
+ */
+ SAA716x_EPWR(GREG, GREG_PMCSR_DATA_2, 0x00000000);
+
+ /* #2 Release GREG resets
+ * ip_rst_an
+ * dpa1_rst_an
+ * jetsream_reset_an
+ */
+ SAA716x_EPWR(GREG, GREG_RSTU_CTRL, 0x00000e00);
+
+ /* #3 GPIO Setup
+ * GPIO 25:24 = Output
+ * GPIO Output "0" after Reset
+ */
+ SAA716x_EPWR(GPIO, GPIO_OEN, 0xfcffffff);
+
+ /* #4 Custom stuff goes in here */
+
+ /* #5 Disable CGU Clocks
+ * except for PHY, Jetstream, DPA1, DCS, Boot, GREG
+ * CGU_PCR_0_3: pss_mmu_clk:0 = 0x0
+ */
+ SAA716x_EPWR(CGU, CGU_PCR_0_3, 0x00000006);
+
+ /* CGU_PCR_0_4: pss_dtl2mtl_mmu_clk:0 = 0x0 */
+ SAA716x_EPWR(CGU, CGU_PCR_0_4, 0x00000006);
+
+ /* CGU_PCR_0_5: pss_msi_ck:0 = 0x0 */
+ SAA716x_EPWR(CGU, CGU_PCR_0_5, 0x00000006);
+
+ /* CGU_PCR_0_7: pss_gpio_clk:0 = 0x0 */
+ SAA716x_EPWR(CGU, CGU_PCR_0_7, 0x00000006);
+
+ /* CGU_PCR_2_1: spi_clk:0 = 0x0 */
+ SAA716x_EPWR(CGU, CGU_PCR_2_1, 0x00000006);
+
+ /* CGU_PCR_3_2: i2c_clk:0 = 0x0 */
+ SAA716x_EPWR(CGU, CGU_PCR_3_2, 0x00000006);
+
+ /* CGU_PCR_4_1: phi_clk:0 = 0x0 */
+ SAA716x_EPWR(CGU, CGU_PCR_4_1, 0x00000006);
+
+ /* CGU_PCR_5: vip0_clk:0 = 0x0 */
+ SAA716x_EPWR(CGU, CGU_PCR_5, 0x00000006);
+
+ /* CGU_PCR_6: vip1_clk:0 = 0x0 */
+ SAA716x_EPWR(CGU, CGU_PCR_6, 0x00000006);
+
+ /* CGU_PCR_7: fgpi0_clk:0 = 0x0 */
+ SAA716x_EPWR(CGU, CGU_PCR_7, 0x00000006);
+
+ /* CGU_PCR_8: fgpi1_clk:0 = 0x0 */
+ SAA716x_EPWR(CGU, CGU_PCR_8, 0x00000006);
+
+ /* CGU_PCR_9: fgpi2_clk:0 = 0x0 */
+ SAA716x_EPWR(CGU, CGU_PCR_9, 0x00000006);
+
+ /* CGU_PCR_10: fgpi3_clk:0 = 0x0 */
+ SAA716x_EPWR(CGU, CGU_PCR_10, 0x00000006);
+
+ /* CGU_PCR_11: ai0_clk:0 = 0x0 */
+ SAA716x_EPWR(CGU, CGU_PCR_11, 0x00000006);
+
+ /* CGU_PCR_12: ai1_clk:0 = 0x0 */
+ SAA716x_EPWR(CGU, CGU_PCR_12, 0x00000006);
+
+ /* #6 Set GREG boot_ready = 0x1 */
+ SAA716x_EPWR(GREG, GREG_RSTU_CTRL, 0x00002000);
+
+ /* #7 Disable GREG CGU Clock */
+ SAA716x_EPWR(CGU, CGU_PCR_0_6, 0x00000006);
+
+ /* End of Bootscript command ?? */
+}
+
+int saa716x_core_boot(struct saa716x_dev *saa716x)
+{
+ struct saa716x_config *config = saa716x->config;
+
+ switch (config->boot_mode) {
+ case SAA716x_EXT_BOOT:
+ dprintk(SAA716x_DEBUG, 1, "Using External Boot from config");
+ saa716x_ext_boot(saa716x);
+ break;
+ case SAA716x_INT_BOOT:
+ dprintk(SAA716x_DEBUG, 1, "Using Internal Boot from config");
+ saa716x_int_boot(saa716x);
+ break;
+ default:
+ dprintk(SAA716x_ERROR, 1, "Unknown configuration %d", config->boot_mode);
+ break;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa716x_core_boot);
+
+static void saa716x_bus_report(struct pci_dev *pdev, int enable)
+{
+ u32 reg;
+
+ pci_read_config_dword(pdev, 0x04, &reg);
+ if (enable)
+ reg |= 0x00000100; /* enable SERR */
+ else
+ reg &= 0xfffffeff; /* disable SERR */
+ pci_write_config_dword(pdev, 0x04, reg);
+
+ pci_read_config_dword(pdev, 0x58, &reg);
+ reg &= 0xfffffffd;
+ pci_write_config_dword(pdev, 0x58, reg);
+}
+
+int saa716x_jetpack_init(struct saa716x_dev *saa716x)
+{
+ /*
+ * configure PHY through config space not to report
+ * non-fatal error messages to avoid problems with
+ * quirky BIOS'es
+ */
+ saa716x_bus_report(saa716x->pdev, 0);
+
+ /*
+ * create time out for blocks that have no clock
+ * helps with lower bitrates on FGPI
+ */
+ SAA716x_EPWR(DCS, DCSC_CTRL, ENABLE_TIMEOUT);
+
+ /* Reset all blocks */
+ SAA716x_EPWR(MSI, MSI_SW_RST, MSI_SW_RESET);
+ SAA716x_EPWR(MMU, MMU_SW_RST, MMU_SW_RESET);
+ SAA716x_EPWR(BAM, BAM_SW_RST, BAM_SW_RESET);
+
+ switch (saa716x->pdev->device) {
+ case SAA7162:
+ dprintk(SAA716x_DEBUG, 1, "SAA%02x Decoder disable", saa716x->pdev->device);
+ SAA716x_EPWR(GPIO, GPIO_OEN, 0xfcffffff);
+ SAA716x_EPWR(GPIO, GPIO_WR, 0x00000000); /* Disable decoders */
+ msleep(10);
+ SAA716x_EPWR(GPIO, GPIO_WR, 0x03000000); /* Enable decoders */
+ break;
+ case SAA7161:
+ dprintk(SAA716x_DEBUG, 1, "SAA%02x Decoder disable", saa716x->pdev->device);
+ SAA716x_EPWR(GPIO, GPIO_OEN, 0xfeffffff);
+ SAA716x_EPWR(GPIO, GPIO_WR, 0x00000000); /* Disable decoders */
+ msleep(10);
+ SAA716x_EPWR(GPIO, GPIO_WR, 0x01000000); /* Enable decoder */
+ break;
+ case SAA7160:
+ saa716x->i2c_rate = SAA716x_I2C_RATE_100;
+ break;
+ default:
+ dprintk(SAA716x_ERROR, 1, "Unknown device (0x%02x)", saa716x->pdev->device);
+ return -ENODEV;
+ }
+
+ /* General setup for MMU */
+ SAA716x_EPWR(MMU, MMU_MODE, 0x14);
+ dprintk(SAA716x_DEBUG, 1, "SAA%02x Jetpack Successfully initialized", saa716x->pdev->device);
+
+ return 0;
+}
+EXPORT_SYMBOL(saa716x_jetpack_init);
+
+void saa716x_core_reset(struct saa716x_dev *saa716x)
+{
+ dprintk(SAA716x_DEBUG, 1, "RESET Modules");
+
+ /* VIP */
+ SAA716x_EPWR(VI0, VI_MODE, SOFT_RESET);
+ SAA716x_EPWR(VI1, VI_MODE, SOFT_RESET);
+
+ /* FGPI */
+ SAA716x_EPWR(FGPI0, FGPI_SOFT_RESET, FGPI_SOFTWARE_RESET);
+ SAA716x_EPWR(FGPI1, FGPI_SOFT_RESET, FGPI_SOFTWARE_RESET);
+ SAA716x_EPWR(FGPI2, FGPI_SOFT_RESET, FGPI_SOFTWARE_RESET);
+ SAA716x_EPWR(FGPI3, FGPI_SOFT_RESET, FGPI_SOFTWARE_RESET);
+
+ /* AIP */
+ SAA716x_EPWR(AI0, AI_CTL, AI_RESET);
+ SAA716x_EPWR(AI1, AI_CTL, AI_RESET);
+
+ /* BAM */
+ SAA716x_EPWR(BAM, BAM_SW_RST, BAM_SW_RESET);
+
+ /* MMU */
+ SAA716x_EPWR(MMU, MMU_SW_RST, MMU_SW_RESET);
+
+ /* MSI */
+ SAA716x_EPWR(MSI, MSI_SW_RST, MSI_SW_RESET);
+}
+EXPORT_SYMBOL_GPL(saa716x_core_reset);
diff --git a/drivers/media/common/saa716x/saa716x_boot.h b/drivers/media/common/saa716x/saa716x_boot.h
new file mode 100644
index 0000000..8102853
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_boot.h
@@ -0,0 +1,18 @@
+#ifndef __SAA716x_BOOT_H
+#define __SAA716x_BOOT_H
+
+#define DISABLE_TIMEOUT 0x17
+#define ENABLE_TIMEOUT 0x16
+
+enum saa716x_boot_mode {
+ SAA716x_EXT_BOOT = 1,
+ SAA716x_INT_BOOT, /* GPIO[31:30] = 0x01 */
+};
+
+struct saa716x_dev;
+
+extern int saa716x_core_boot(struct saa716x_dev *saa716x);
+extern int saa716x_jetpack_init(struct saa716x_dev *saa716x);
+extern void saa716x_core_reset(struct saa716x_dev *saa716x);
+
+#endif /* __SAA716x_BOOT_H */
diff --git a/drivers/media/common/saa716x/saa716x_budget.c b/drivers/media/common/saa716x/saa716x_budget.c
new file mode 100644
index 0000000..6b52fc1
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_budget.c
@@ -0,0 +1,717 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/mutex.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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include <linux/i2c.h>
+
+#include "saa716x_mod.h"
+
+#include "saa716x_gpio_reg.h"
+#include "saa716x_greg_reg.h"
+#include "saa716x_msi_reg.h"
+
+#include "saa716x_adap.h"
+#include "saa716x_i2c.h"
+#include "saa716x_msi.h"
+#include "saa716x_budget.h"
+#include "saa716x_gpio.h"
+#include "saa716x_rom.h"
+#include "saa716x_spi.h"
+#include "saa716x_priv.h"
+
+#include "mb86a16.h"
+#include "stv6110x.h"
+#include "stv090x.h"
+#include "ds3103.h"
+#include "ts2022.h"
+
+unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+
+unsigned int int_type;
+module_param(int_type, int, 0644);
+MODULE_PARM_DESC(int_type, "force Interrupt Handler type: 0=INT-A, 1=MSI, 2=MSI-X. default INT-A mode");
+
+#define DRIVER_NAME "SAA716x Budget"
+
+static int saa716x_budget_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+ struct saa716x_dev *saa716x;
+ int err = 0;
+
+ saa716x = kzalloc(sizeof (struct saa716x_dev), GFP_KERNEL);
+ if (saa716x == NULL) {
+ printk(KERN_ERR "saa716x_budget_pci_probe ERROR: out of memory\n");
+ err = -ENOMEM;
+ goto fail0;
+ }
+
+ saa716x->verbose = verbose;
+ saa716x->int_type = int_type;
+ saa716x->pdev = pdev;
+ saa716x->config = (struct saa716x_config *) pci_id->driver_data;
+
+ err = saa716x_pci_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x PCI Initialization failed");
+ goto fail1;
+ }
+
+ err = saa716x_cgu_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x CGU Init failed");
+ goto fail1;
+ }
+
+ err = saa716x_core_boot(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x Core Boot failed");
+ goto fail2;
+ }
+ dprintk(SAA716x_DEBUG, 1, "SAA716x Core Boot Success");
+
+ err = saa716x_msi_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x MSI Init failed");
+ goto fail2;
+ }
+
+ err = saa716x_jetpack_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x Jetpack core initialization failed");
+ goto fail1;
+ }
+
+ err = saa716x_i2c_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x I2C Initialization failed");
+ goto fail3;
+ }
+
+ saa716x_gpio_init(saa716x);
+
+ err = saa716x_dump_eeprom(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x EEPROM dump failed");
+ }
+
+ err = saa716x_eeprom_data(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x EEPROM read failed");
+ }
+
+ /* set default port mapping */
+ SAA716x_EPWR(GREG, GREG_VI_CTRL, 0x04080FA9);
+ /* enable FGPI3 and FGPI1 for TS input from Port 2 and 6 */
+ SAA716x_EPWR(GREG, GREG_FGPI_CTRL, 0x321);
+
+ err = saa716x_dvb_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x DVB initialization failed");
+ goto fail4;
+ }
+
+ return 0;
+
+fail4:
+ saa716x_dvb_exit(saa716x);
+fail3:
+ saa716x_i2c_exit(saa716x);
+fail2:
+ saa716x_pci_exit(saa716x);
+fail1:
+ kfree(saa716x);
+fail0:
+ return err;
+}
+
+static void saa716x_budget_pci_remove(struct pci_dev *pdev)
+{
+ struct saa716x_dev *saa716x = pci_get_drvdata(pdev);
+
+ saa716x_dvb_exit(saa716x);
+ saa716x_i2c_exit(saa716x);
+ saa716x_pci_exit(saa716x);
+ kfree(saa716x);
+}
+
+static irqreturn_t saa716x_budget_pci_irq(int irq, void *dev_id)
+{
+ struct saa716x_dev *saa716x = (struct saa716x_dev *) dev_id;
+
+ u32 stat_h, stat_l, mask_h, mask_l;
+
+ if (unlikely(saa716x == NULL)) {
+ printk("%s: saa716x=NULL", __func__);
+ return IRQ_NONE;
+ }
+
+ stat_l = SAA716x_EPRD(MSI, MSI_INT_STATUS_L);
+ stat_h = SAA716x_EPRD(MSI, MSI_INT_STATUS_H);
+ mask_l = SAA716x_EPRD(MSI, MSI_INT_ENA_L);
+ mask_h = SAA716x_EPRD(MSI, MSI_INT_ENA_H);
+
+ dprintk(SAA716x_DEBUG, 1, "MSI STAT L=<%02x> H=<%02x>, CTL L=<%02x> H=<%02x>",
+ stat_l, stat_h, mask_l, mask_h);
+
+ if (!((stat_l & mask_l) || (stat_h & mask_h)))
+ return IRQ_NONE;
+
+ if (stat_l)
+ SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_L, stat_l);
+
+ if (stat_h)
+ SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_H, stat_h);
+
+ saa716x_msi_event(saa716x, stat_l, stat_h);
+#if 0
+ dprintk(SAA716x_DEBUG, 1, "VI STAT 0=<%02x> 1=<%02x>, CTL 1=<%02x> 2=<%02x>",
+ SAA716x_EPRD(VI0, INT_STATUS),
+ SAA716x_EPRD(VI1, INT_STATUS),
+ SAA716x_EPRD(VI0, INT_ENABLE),
+ SAA716x_EPRD(VI1, INT_ENABLE));
+
+ dprintk(SAA716x_DEBUG, 1, "FGPI STAT 0=<%02x> 1=<%02x>, CTL 1=<%02x> 2=<%02x>",
+ SAA716x_EPRD(FGPI0, INT_STATUS),
+ SAA716x_EPRD(FGPI1, INT_STATUS),
+ SAA716x_EPRD(FGPI0, INT_ENABLE),
+ SAA716x_EPRD(FGPI0, INT_ENABLE));
+
+ dprintk(SAA716x_DEBUG, 1, "FGPI STAT 2=<%02x> 3=<%02x>, CTL 2=<%02x> 3=<%02x>",
+ SAA716x_EPRD(FGPI2, INT_STATUS),
+ SAA716x_EPRD(FGPI3, INT_STATUS),
+ SAA716x_EPRD(FGPI2, INT_ENABLE),
+ SAA716x_EPRD(FGPI3, INT_ENABLE));
+
+ dprintk(SAA716x_DEBUG, 1, "AI STAT 0=<%02x> 1=<%02x>, CTL 0=<%02x> 1=<%02x>",
+ SAA716x_EPRD(AI0, AI_STATUS),
+ SAA716x_EPRD(AI1, AI_STATUS),
+ SAA716x_EPRD(AI0, AI_CTL),
+ SAA716x_EPRD(AI1, AI_CTL));
+
+ dprintk(SAA716x_DEBUG, 1, "I2C STAT 0=<%02x> 1=<%02x>, CTL 0=<%02x> 1=<%02x>",
+ SAA716x_EPRD(I2C_A, INT_STATUS),
+ SAA716x_EPRD(I2C_B, INT_STATUS),
+ SAA716x_EPRD(I2C_A, INT_ENABLE),
+ SAA716x_EPRD(I2C_B, INT_ENABLE));
+
+ dprintk(SAA716x_DEBUG, 1, "DCS STAT=<%02x>, CTL=<%02x>",
+ SAA716x_EPRD(DCS, DCSC_INT_STATUS),
+ SAA716x_EPRD(DCS, DCSC_INT_ENABLE));
+#endif
+
+ if (stat_l) {
+ if (stat_l & MSI_INT_TAGACK_FGPI_0) {
+ tasklet_schedule(&saa716x->fgpi[0].tasklet);
+ }
+ if (stat_l & MSI_INT_TAGACK_FGPI_1) {
+ tasklet_schedule(&saa716x->fgpi[1].tasklet);
+ }
+ if (stat_l & MSI_INT_TAGACK_FGPI_2) {
+ tasklet_schedule(&saa716x->fgpi[2].tasklet);
+ }
+ if (stat_l & MSI_INT_TAGACK_FGPI_3) {
+ tasklet_schedule(&saa716x->fgpi[3].tasklet);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void demux_worker(unsigned long data)
+{
+ struct saa716x_fgpi_stream_port *fgpi_entry = (struct saa716x_fgpi_stream_port *)data;
+ struct saa716x_dev *saa716x = fgpi_entry->saa716x;
+ struct dvb_demux *demux;
+ u32 fgpi_index;
+ u32 i;
+ u32 write_index;
+
+ fgpi_index = fgpi_entry->dma_channel - 6;
+ demux = NULL;
+ for (i = 0; i < saa716x->config->adapters; i++) {
+ if (saa716x->config->adap_config[i].ts_port == fgpi_index) {
+ demux = &saa716x->saa716x_adap[i].demux;
+ break;
+ }
+ }
+ if (demux == NULL) {
+ printk(KERN_ERR "%s: unexpected channel %u\n",
+ __func__, fgpi_entry->dma_channel);
+ return;
+ }
+
+ write_index = saa716x_fgpi_get_write_index(saa716x, fgpi_index);
+ if (write_index < 0)
+ return;
+
+ dprintk(SAA716x_DEBUG, 1, "dma buffer = %d", write_index);
+
+ if (write_index == fgpi_entry->read_index) {
+ printk(KERN_DEBUG "%s: called but nothing to do\n", __func__);
+ return;
+ }
+
+ do {
+ u8 *data = (u8 *)fgpi_entry->dma_buf[fgpi_entry->read_index].mem_virt;
+
+ pci_dma_sync_sg_for_cpu(saa716x->pdev,
+ fgpi_entry->dma_buf[fgpi_entry->read_index].sg_list,
+ fgpi_entry->dma_buf[fgpi_entry->read_index].list_len,
+ PCI_DMA_FROMDEVICE);
+
+ dvb_dmx_swfilter(demux, data, 348 * 188);
+
+ fgpi_entry->read_index = (fgpi_entry->read_index + 1) & 7;
+ } while (write_index != fgpi_entry->read_index);
+}
+
+
+#define SAA716x_MODEL_TWINHAN_VP3071 "Twinhan/Azurewave VP-3071"
+#define SAA716x_DEV_TWINHAN_VP3071 "2x DVB-T"
+
+static int saa716x_vp3071_frontend_attach(struct saa716x_adapter *adapter, int count)
+{
+ struct saa716x_dev *saa716x = adapter->saa716x;
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", count);
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device);
+
+ return -ENODEV;
+}
+
+static struct saa716x_config saa716x_vp3071_config = {
+ .model_name = SAA716x_MODEL_TWINHAN_VP3071,
+ .dev_type = SAA716x_DEV_TWINHAN_VP3071,
+ .boot_mode = SAA716x_EXT_BOOT,
+ .adapters = 2,
+ .frontend_attach = saa716x_vp3071_frontend_attach,
+ .irq_handler = saa716x_budget_pci_irq,
+ .i2c_rate = SAA716x_I2C_RATE_100,
+};
+
+
+#define SAA716x_MODEL_TWINHAN_VP1028 "Twinhan/Azurewave VP-1028"
+#define SAA716x_DEV_TWINHAN_VP1028 "DVB-S"
+
+static int vp1028_dvbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct saa716x_dev *saa716x = fe->dvb->priv;
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ dprintk(SAA716x_ERROR, 1, "Polarization=[13V]");
+ break;
+ case SEC_VOLTAGE_18:
+ dprintk(SAA716x_ERROR, 1, "Polarization=[18V]");
+ break;
+ case SEC_VOLTAGE_OFF:
+ dprintk(SAA716x_ERROR, 1, "Frontend (dummy) POWERDOWN");
+ break;
+ default:
+ dprintk(SAA716x_ERROR, 1, "Invalid = (%d)", (u32 ) voltage);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+struct mb86a16_config vp1028_mb86a16_config = {
+ .demod_address = 0x08,
+ .set_voltage = vp1028_dvbs_set_voltage,
+};
+
+static int saa716x_vp1028_frontend_attach(struct saa716x_adapter *adapter, int count)
+{
+ struct saa716x_dev *saa716x = adapter->saa716x;
+ struct saa716x_i2c *i2c = &saa716x->i2c[1];
+
+ if (count == 0) {
+
+ mutex_lock(&saa716x->adap_lock);
+
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Power ON", count);
+ saa716x_gpio_set_output(saa716x, 10);
+ msleep(1);
+
+ /* VP-1028 has inverted power supply control */
+ saa716x_gpio_write(saa716x, 10, 1); /* set to standby */
+ saa716x_gpio_write(saa716x, 10, 0); /* switch it on */
+ msleep(100);
+
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Reset", count);
+ saa716x_gpio_set_output(saa716x, 12);
+ msleep(1);
+
+ /* reset demodulator (Active LOW) */
+ saa716x_gpio_write(saa716x, 12, 1);
+ msleep(100);
+ saa716x_gpio_write(saa716x, 12, 0);
+ msleep(100);
+ saa716x_gpio_write(saa716x, 12, 1);
+ msleep(100);
+
+ mutex_unlock(&saa716x->adap_lock);
+
+ dprintk(SAA716x_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)");
+ adapter->fe = mb86a16_attach(&vp1028_mb86a16_config, &i2c->i2c_adapter);
+ if (adapter->fe) {
+ dprintk(SAA716x_ERROR, 1, "found MB86A16 DVB-S/DSS frontend @0x%02x",
+ vp1028_mb86a16_config.demod_address);
+
+ } else {
+ goto exit;
+ }
+ dprintk(SAA716x_ERROR, 1, "Done!");
+ }
+
+ return 0;
+exit:
+ dprintk(SAA716x_ERROR, 1, "Frontend attach failed");
+ return -ENODEV;
+}
+
+static struct saa716x_config saa716x_vp1028_config = {
+ .model_name = SAA716x_MODEL_TWINHAN_VP1028,
+ .dev_type = SAA716x_DEV_TWINHAN_VP1028,
+ .boot_mode = SAA716x_EXT_BOOT,
+ .adapters = 1,
+ .frontend_attach = saa716x_vp1028_frontend_attach,
+ .irq_handler = saa716x_budget_pci_irq,
+ .i2c_rate = SAA716x_I2C_RATE_100,
+};
+
+
+#define SAA716x_MODEL_TWINHAN_VP6002 "Twinhan/Azurewave VP-6002"
+#define SAA716x_DEV_TWINHAN_VP6002 "DVB-S"
+
+static int saa716x_vp6002_frontend_attach(struct saa716x_adapter *adapter, int count)
+{
+ struct saa716x_dev *saa716x = adapter->saa716x;
+
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", count);
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device);
+
+ return -ENODEV;
+}
+
+static struct saa716x_config saa716x_vp6002_config = {
+ .model_name = SAA716x_MODEL_TWINHAN_VP6002,
+ .dev_type = SAA716x_DEV_TWINHAN_VP6002,
+ .boot_mode = SAA716x_EXT_BOOT,
+ .adapters = 1,
+ .frontend_attach = saa716x_vp6002_frontend_attach,
+ .irq_handler = saa716x_budget_pci_irq,
+ .i2c_rate = SAA716x_I2C_RATE_100,
+};
+
+
+#define SAA716x_MODEL_KNC1_DUALS2 "KNC One Dual S2"
+#define SAA716x_DEV_KNC1_DUALS2 "1xDVB-S + 1xDVB-S/S2"
+
+static int saa716x_knc1_duals2_frontend_attach(struct saa716x_adapter *adapter, int count)
+{
+ struct saa716x_dev *saa716x = adapter->saa716x;
+
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", count);
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device);
+
+ return -ENODEV;
+}
+
+static struct saa716x_config saa716x_knc1_duals2_config = {
+ .model_name = SAA716x_MODEL_KNC1_DUALS2,
+ .dev_type = SAA716x_DEV_KNC1_DUALS2,
+ .boot_mode = SAA716x_EXT_BOOT,
+ .adapters = 2,
+ .frontend_attach = saa716x_knc1_duals2_frontend_attach,
+ .irq_handler = saa716x_budget_pci_irq,
+ .i2c_rate = SAA716x_I2C_RATE_100,
+};
+
+
+#define SAA716x_MODEL_SKYSTAR2_EXPRESS_HD "SkyStar 2 eXpress HD"
+#define SAA716x_DEV_SKYSTAR2_EXPRESS_HD "DVB-S/S2"
+
+static struct stv090x_config skystar2_stv090x_config = {
+ .device = STV0903,
+ .demod_mode = STV090x_SINGLE,
+ .clk_mode = STV090x_CLK_EXT,
+
+ .xtal = 8000000,
+ .address = 0x68,
+
+ .ts1_mode = STV090x_TSMODE_DVBCI,
+ .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS,
+
+ .repeater_level = STV090x_RPTLEVEL_16,
+
+ .tuner_init = NULL,
+ .tuner_sleep = NULL,
+ .tuner_set_mode = NULL,
+ .tuner_set_frequency = NULL,
+ .tuner_get_frequency = NULL,
+ .tuner_set_bandwidth = NULL,
+ .tuner_get_bandwidth = NULL,
+ .tuner_set_bbgain = NULL,
+ .tuner_get_bbgain = NULL,
+ .tuner_set_refclk = NULL,
+ .tuner_get_status = NULL,
+};
+
+static int skystar2_set_voltage(struct dvb_frontend *fe,
+ enum fe_sec_voltage voltage)
+{
+ int err;
+ u8 en = 0;
+ u8 sel = 0;
+
+ switch (voltage) {
+ case SEC_VOLTAGE_OFF:
+ en = 0;
+ break;
+
+ case SEC_VOLTAGE_13:
+ en = 1;
+ sel = 0;
+ break;
+
+ case SEC_VOLTAGE_18:
+ en = 1;
+ sel = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ err = stv090x_set_gpio(fe, 2, 0, en, 0);
+ if (err < 0)
+ goto exit;
+ err = stv090x_set_gpio(fe, 3, 0, sel, 0);
+ if (err < 0)
+ goto exit;
+
+ return 0;
+exit:
+ return err;
+}
+
+static int skystar2_voltage_boost(struct dvb_frontend *fe, long arg)
+{
+ int err;
+ u8 value;
+
+ if (arg)
+ value = 1;
+ else
+ value = 0;
+
+ err = stv090x_set_gpio(fe, 4, 0, value, 0);
+ if (err < 0)
+ goto exit;
+
+ return 0;
+exit:
+ return err;
+}
+
+static struct stv6110x_config skystar2_stv6110x_config = {
+ .addr = 0x60,
+ .refclk = 16000000,
+ .clk_div = 2,
+};
+
+static int skystar2_express_hd_frontend_attach(struct saa716x_adapter *adapter,
+ int count)
+{
+ struct saa716x_dev *saa716x = adapter->saa716x;
+ struct saa716x_i2c *i2c = &saa716x->i2c[SAA716x_I2C_BUS_B];
+ struct stv6110x_devctl *ctl;
+
+ if (count < saa716x->config->adapters) {
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init",
+ count);
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count,
+ saa716x->pdev->subsystem_device);
+
+ saa716x_gpio_set_output(saa716x, 26);
+
+ /* Reset the demodulator */
+ saa716x_gpio_write(saa716x, 26, 1);
+ msleep(10);
+ saa716x_gpio_write(saa716x, 26, 0);
+ msleep(10);
+ saa716x_gpio_write(saa716x, 26, 1);
+ msleep(10);
+
+ adapter->fe = dvb_attach(stv090x_attach,
+ &skystar2_stv090x_config,
+ &i2c->i2c_adapter,
+ STV090x_DEMODULATOR_0);
+
+ if (adapter->fe) {
+ dprintk(SAA716x_NOTICE, 1, "found STV0903 @0x%02x",
+ skystar2_stv090x_config.address);
+ } else {
+ goto exit;
+ }
+
+ adapter->fe->ops.set_voltage = skystar2_set_voltage;
+ adapter->fe->ops.enable_high_lnb_voltage = skystar2_voltage_boost;
+
+ ctl = dvb_attach(stv6110x_attach,
+ adapter->fe,
+ &skystar2_stv6110x_config,
+ &i2c->i2c_adapter);
+
+ if (ctl) {
+ dprintk(SAA716x_NOTICE, 1, "found STV6110(A) @0x%02x",
+ skystar2_stv6110x_config.addr);
+
+ skystar2_stv090x_config.tuner_init = ctl->tuner_init;
+ skystar2_stv090x_config.tuner_sleep = ctl->tuner_sleep;
+ skystar2_stv090x_config.tuner_set_mode = ctl->tuner_set_mode;
+ skystar2_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
+ skystar2_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
+ skystar2_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+ skystar2_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+ skystar2_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain;
+ skystar2_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain;
+ skystar2_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk;
+ skystar2_stv090x_config.tuner_get_status = ctl->tuner_get_status;
+
+ /* call the init function once to initialize
+ tuner's clock output divider and demod's
+ master clock */
+ if (adapter->fe->ops.init)
+ adapter->fe->ops.init(adapter->fe);
+ } else {
+ goto exit;
+ }
+
+ dprintk(SAA716x_ERROR, 1, "Done!");
+ return 0;
+ }
+exit:
+ dprintk(SAA716x_ERROR, 1, "Frontend attach failed");
+ return -ENODEV;
+}
+
+static struct saa716x_config skystar2_express_hd_config = {
+ .model_name = SAA716x_MODEL_SKYSTAR2_EXPRESS_HD,
+ .dev_type = SAA716x_DEV_SKYSTAR2_EXPRESS_HD,
+ .boot_mode = SAA716x_EXT_BOOT,
+ .adapters = 1,
+ .frontend_attach = skystar2_express_hd_frontend_attach,
+ .irq_handler = saa716x_budget_pci_irq,
+ .i2c_rate = SAA716x_I2C_RATE_100,
+ .adap_config = {
+ {
+ /* Adapter 0 */
+ .ts_port = 1, /* using FGPI 1 */
+ .worker = demux_worker
+ }
+ }
+};
+
+static struct ds3103_config s472_ds3103_config = {
+ .demod_address = 0x68,
+ .ci_mode = 1,
+};
+
+static int saa716x_s472_frontend_attach(struct saa716x_adapter *adapter, int count)
+{
+ struct saa716x_dev *saa716x = adapter->saa716x;
+ struct saa716x_i2c *i2c = &saa716x->i2c[1];
+
+ if (count != 0)
+ return 0;
+
+ dprintk(SAA716x_ERROR, 1, "Probing for DS3103 (DVB-S/S2)");
+ adapter->fe = dvb_attach(ds3103_attach, &s472_ds3103_config,
+ &i2c->i2c_adapter);
+
+ if (adapter->fe == NULL) {
+ dprintk(SAA716x_ERROR, 1, "Frontend attach failed");
+ return -ENODEV;
+ }
+
+ dprintk(SAA716x_ERROR, 1, "found DS3103 DVB-S/S2 frontend @0x%02x",
+ s472_ds3103_config.demod_address);
+ if (NULL == dvb_attach(ts2022_attach, adapter->fe, 0x60, &i2c->i2c_adapter))
+ dprintk(SAA716x_ERROR, 1, "ts2022 attach failed");
+ else
+ dprintk(SAA716x_ERROR, 1, "ts2022 attached!");
+
+ dprintk(SAA716x_ERROR, 1, "Done!");
+ return 0;
+
+}
+
+static struct saa716x_config tevii_s472_config = {
+ .model_name = "TeVii S472 DVB-S2",
+ .dev_type = "DVB-S/S2",
+ .boot_mode = SAA716x_EXT_BOOT,
+ .adapters = 1,
+ .frontend_attach = saa716x_s472_frontend_attach,
+ .irq_handler = saa716x_budget_pci_irq,
+ .i2c_rate = SAA716x_I2C_RATE_100,
+ .adap_config = {
+ {
+ /* Adapter 0 */
+ .ts_port = 1, /* using FGPI 1 */
+ .worker = demux_worker
+ }
+ }
+};
+
+static struct pci_device_id saa716x_budget_pci_table[] = {
+
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, TWINHAN_VP_1028, SAA7160, &saa716x_vp1028_config), /* VP-1028 */
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, TWINHAN_VP_3071, SAA7160, &saa716x_vp3071_config), /* VP-3071 */
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, TWINHAN_VP_6002, SAA7160, &saa716x_vp6002_config), /* VP-6002 */
+ MAKE_ENTRY(KNC_One, KNC_Dual_S2, SAA7160, &saa716x_knc1_duals2_config),
+ MAKE_ENTRY(TECHNISAT, SKYSTAR2_EXPRESS_HD, SAA7160, &skystar2_express_hd_config),
+ MAKE_ENTRY(TEVII, TEVII_S472, SAA7160, &tevii_s472_config),
+ { }
+};
+MODULE_DEVICE_TABLE(pci, saa716x_budget_pci_table);
+
+static struct pci_driver saa716x_budget_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = saa716x_budget_pci_table,
+ .probe = saa716x_budget_pci_probe,
+ .remove = saa716x_budget_pci_remove,
+};
+
+static int saa716x_budget_init(void)
+{
+ return pci_register_driver(&saa716x_budget_pci_driver);
+}
+
+static void saa716x_budget_exit(void)
+{
+ return pci_unregister_driver(&saa716x_budget_pci_driver);
+}
+
+module_init(saa716x_budget_init);
+module_exit(saa716x_budget_exit);
+
+MODULE_DESCRIPTION("SAA716x Budget driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/saa716x/saa716x_budget.h b/drivers/media/common/saa716x/saa716x_budget.h
new file mode 100644
index 0000000..d6b8c46
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_budget.h
@@ -0,0 +1,17 @@
+#ifndef __SAA716x_BUDGET_H
+#define __SAA716x_BUDGET_H
+
+#define TWINHAN_TECHNOLOGIES 0x1822
+#define TWINHAN_VP_3071 0x0039
+#define TWINHAN_VP_1028 0x0044
+#define TWINHAN_VP_6002 0x0047
+
+#define KNC_One 0x1894
+#define KNC_Dual_S2 0x0110
+
+#define TECHNISAT 0x1AE4
+#define SKYSTAR2_EXPRESS_HD 0x0700
+#define TEVII 0x9022
+#define TEVII_S472 0xd472
+
+#endif /* __SAA716x_BUDGET_H */
diff --git a/drivers/media/common/saa716x/saa716x_cgu.c b/drivers/media/common/saa716x/saa716x_cgu.c
new file mode 100644
index 0000000..a0ffb04
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_cgu.c
@@ -0,0 +1,539 @@
+#include <linux/delay.h>
+
+#include "saa716x_mod.h"
+
+#include "saa716x_cgu_reg.h"
+#include "saa716x_spi.h"
+#include "saa716x_priv.h"
+
+u32 cgu_clk[14] = {
+ CGU_FDC_0,
+ CGU_FDC_1,
+ CGU_FDC_2,
+ CGU_FDC_3,
+ CGU_FDC_4,
+ CGU_FDC_5,
+ CGU_FDC_6,
+ CGU_FDC_7,
+ CGU_FDC_8,
+ CGU_FDC_9,
+ CGU_FDC_10,
+ CGU_FDC_11,
+ CGU_FDC_12,
+ CGU_FDC_13
+};
+
+char *clk_desc[14] = {
+ "Clk PSS",
+ "Clk DCS",
+ "Clk SPI",
+ "Clk I2C/Boot",
+ "Clk PHI",
+ "Clk VI0",
+ "Clk VI1",
+ "Clk FGPI0",
+ "Clk FGPI1",
+ "Clk FGPI2",
+ "Clk FGPI3",
+ "Clk AI0",
+ "Clk AI1",
+ "Clk Phy"
+};
+
+int saa716x_getbootscript_setup(struct saa716x_dev *saa716x)
+{
+ struct saa716x_cgu *cgu = &saa716x->cgu;
+
+ u8 i;
+ s8 N = 0;
+ s16 M = 0;
+
+ SAA716x_EPWR(CGU, CGU_PCR_0_6, CGU_PCR_RUN); /* GREG */
+ SAA716x_EPWR(CGU, CGU_PCR_0_3, CGU_PCR_RUN); /* PSS_MMU */
+ SAA716x_EPWR(CGU, CGU_PCR_0_4, CGU_PCR_RUN); /* PSS_DTL2MTL */
+ SAA716x_EPWR(CGU, CGU_PCR_0_5, CGU_PCR_RUN); /* MSI */
+ SAA716x_EPWR(CGU, CGU_PCR_3_2, CGU_PCR_RUN); /* I2C */
+ SAA716x_EPWR(CGU, CGU_PCR_4_1, CGU_PCR_RUN); /* PHI */
+ SAA716x_EPWR(CGU, CGU_PCR_0_7, CGU_PCR_RUN); /* GPIO */
+ SAA716x_EPWR(CGU, CGU_PCR_2_1, CGU_PCR_RUN); /* SPI */
+ SAA716x_EPWR(CGU, CGU_PCR_1_1, CGU_PCR_RUN); /* DCS */
+ SAA716x_EPWR(CGU, CGU_PCR_3_1, CGU_PCR_RUN); /* BOOT */
+
+ /* get all dividers */
+ for (i = 0; i < CGU_CLKS; i++) {
+ cgu->clk_boot_div[i] = SAA716x_EPRD(CGU, cgu_clk[i]);
+ cgu->clk_curr_div[i] = cgu->clk_boot_div[i];
+
+ N = (cgu->clk_boot_div[i] >> 11) & 0xff;
+ N *= -1;
+ M = ((cgu->clk_boot_div[i] >> 3) & 0xff) + N;
+
+ if (M)
+ cgu->clk_freq[i] = (u32 ) N * PLL_FREQ / (u32 ) M;
+ else
+ cgu->clk_freq[i] = 0;
+
+ dprintk(SAA716x_DEBUG, 1, "Domain %d: %s <0x%02x> Divider: 0x%x --> N=%d, M=%d, freq=%d",
+ i, clk_desc[i], cgu_clk[i], cgu->clk_boot_div[i], N, M, cgu->clk_freq[i]);
+ }
+ /* store clock settings */
+ cgu->clk_vi_0[0] = cgu->clk_freq[CLK_DOMAIN_VI0];
+ cgu->clk_vi_0[1] = cgu->clk_freq[CLK_DOMAIN_VI0];
+ cgu->clk_vi_0[2] = cgu->clk_freq[CLK_DOMAIN_VI0];
+ cgu->clk_vi_1[0] = cgu->clk_freq[CLK_DOMAIN_VI1];
+ cgu->clk_vi_1[1] = cgu->clk_freq[CLK_DOMAIN_VI1];
+ cgu->clk_vi_1[2] = cgu->clk_freq[CLK_DOMAIN_VI1];
+
+ return 0;
+}
+
+int saa716x_set_clk_internal(struct saa716x_dev *saa716x, u32 port)
+{
+ struct saa716x_cgu *cgu = &saa716x->cgu;
+
+ u8 delay = 1;
+
+ switch (port) {
+ case PORT_VI0_VIDEO:
+ cgu->clk_int_port[PORT_VI0_VIDEO] = 1;
+
+ if (!cgu->clk_int_port[PORT_VI0_VBI]) {
+ delay = 0;
+ break;
+ }
+
+ SAA716x_CGU_CLKRUN(5);
+ break;
+
+ case PORT_VI0_VBI:
+ cgu->clk_int_port[PORT_VI0_VBI] = 1;
+
+ if (!cgu->clk_int_port[PORT_VI0_VIDEO]) {
+ delay = 0;
+ break;
+ }
+
+ SAA716x_CGU_CLKRUN(5);
+ break;
+
+ case PORT_VI1_VIDEO:
+ cgu->clk_int_port[PORT_VI1_VIDEO] = 1;
+
+ if (!cgu->clk_int_port[PORT_VI1_VBI]) {
+ delay = 0;
+ break;
+ }
+
+ SAA716x_CGU_CLKRUN(6);
+ break;
+
+ case PORT_VI1_VBI:
+ cgu->clk_int_port[PORT_VI1_VBI] = 1;
+
+ if (!cgu->clk_int_port[PORT_VI1_VIDEO]) {
+ delay = 0;
+ break;
+ }
+
+ SAA716x_CGU_CLKRUN(6);
+ break;
+
+ case PORT_FGPI0:
+ cgu->clk_int_port[PORT_FGPI0] = 1;
+ SAA716x_CGU_CLKRUN(7);
+ break;
+
+ case PORT_FGPI1:
+ cgu->clk_int_port[PORT_FGPI1] = 1;
+ SAA716x_CGU_CLKRUN(8);
+ break;
+
+ case PORT_FGPI2:
+ cgu->clk_int_port[PORT_FGPI2] = 1;
+ SAA716x_CGU_CLKRUN(9);
+ break;
+
+ case PORT_FGPI3:
+ cgu->clk_int_port[PORT_FGPI3] = 1;
+ SAA716x_CGU_CLKRUN(10);
+ break;
+
+ case PORT_AI0:
+ cgu->clk_int_port[PORT_AI0] = 1;
+ SAA716x_CGU_CLKRUN(11);
+ break;
+
+ case PORT_AI1:
+ cgu->clk_int_port[PORT_AI1] = 1;
+ SAA716x_CGU_CLKRUN(12);
+ break;
+
+ case PORT_ALL:
+ SAA716x_CGU_CLKRUN(5);
+ SAA716x_CGU_CLKRUN(6);
+ SAA716x_CGU_CLKRUN(7);
+ SAA716x_CGU_CLKRUN(8);
+ SAA716x_CGU_CLKRUN(9);
+ SAA716x_CGU_CLKRUN(10);
+ SAA716x_CGU_CLKRUN(11);
+ SAA716x_CGU_CLKRUN(12);
+
+ cgu->clk_int_port[PORT_VI0_VIDEO] = 1;
+ cgu->clk_int_port[PORT_VI0_VBI] = 1;
+ cgu->clk_int_port[PORT_VI1_VIDEO] = 1;
+ cgu->clk_int_port[PORT_VI1_VBI] = 1;
+ cgu->clk_int_port[PORT_FGPI0] = 1;
+ cgu->clk_int_port[PORT_FGPI1] = 1;
+ cgu->clk_int_port[PORT_FGPI2] = 1;
+ cgu->clk_int_port[PORT_FGPI3] = 1;
+ cgu->clk_int_port[PORT_AI0] = 1;
+ cgu->clk_int_port[PORT_AI1] = 1;
+ break;
+
+ default:
+ dprintk(SAA716x_ERROR, 1, "Unknown port <%02x>", port);
+ delay = 0;
+ break;
+ }
+
+ /* wait for PLL */
+ if (delay)
+ msleep(1);
+
+ return 0;
+}
+
+int saa716x_set_clk_external(struct saa716x_dev *saa716x, u32 port)
+{
+ struct saa716x_cgu *cgu = &saa716x->cgu;
+
+ u8 delay = 1;
+
+ switch (port) {
+ case PORT_VI0_VIDEO:
+ cgu->clk_int_port[PORT_VI0_VIDEO] = 0;
+
+ if (!cgu->clk_int_port[PORT_VI0_VBI]) {
+ delay = 0;
+ break;
+ }
+
+ SAA716x_EPWR(CGU, CGU_FS1_5, 0x2); /* VI 0 clk */
+ SAA716x_EPWR(CGU, CGU_ESR_5, 0x0); /* disable divider */
+ break;
+
+ case PORT_VI0_VBI:
+ cgu->clk_int_port[PORT_VI0_VBI] = 0;
+
+ if (!cgu->clk_int_port[PORT_VI0_VIDEO]) {
+ delay = 0;
+ break;
+ }
+
+ SAA716x_EPWR(CGU, CGU_FS1_5, 0x2); /* VI 0 clk */
+ SAA716x_EPWR(CGU, CGU_ESR_5, 0x0); /* disable divider */
+ break;
+
+ case PORT_VI1_VIDEO:
+ cgu->clk_int_port[PORT_VI1_VIDEO] = 0;
+
+ if (!cgu->clk_int_port[PORT_VI1_VBI]) {
+ delay = 0;
+ break;
+ }
+
+ SAA716x_EPWR(CGU, CGU_FS1_6, 0x3); /* VI 1 clk */
+ SAA716x_EPWR(CGU, CGU_ESR_6, 0x0); /* disable divider */
+ break;
+
+ case PORT_VI1_VBI:
+ cgu->clk_int_port[PORT_VI1_VBI] = 0;
+
+ if (!cgu->clk_int_port[PORT_VI1_VIDEO]) {
+ delay = 0;
+ break;
+ }
+
+ SAA716x_EPWR(CGU, CGU_FS1_6, 0x3); /* VI 1 clk */
+ SAA716x_EPWR(CGU, CGU_ESR_6, 0x0); /* disable divider */
+ break;
+
+ case PORT_FGPI0:
+ cgu->clk_int_port[PORT_FGPI0] = 0;
+
+ SAA716x_EPWR(CGU, CGU_FS1_7, 0x4); /* FGPI 0 clk */
+ SAA716x_EPWR(CGU, CGU_ESR_7, 0x0); /* disable divider */
+ break;
+
+ case PORT_FGPI1:
+ cgu->clk_int_port[PORT_FGPI1] = 0;
+
+ SAA716x_EPWR(CGU, CGU_FS1_8, 0x5); /* FGPI 1 clk */
+ SAA716x_EPWR(CGU, CGU_ESR_8, 0x0); /* disable divider */
+ break;
+
+ case PORT_FGPI2:
+ cgu->clk_int_port[PORT_FGPI2] = 0;
+
+ SAA716x_EPWR(CGU, CGU_FS1_9, 0x6); /* FGPI 2 clk */
+ SAA716x_EPWR(CGU, CGU_ESR_9, 0x0); /* disable divider */
+ break;
+
+ case PORT_FGPI3:
+ cgu->clk_int_port[PORT_FGPI3] = 0;
+
+ SAA716x_EPWR(CGU, CGU_FS1_10, 0x7); /* FGPI 3 clk */
+ SAA716x_EPWR(CGU, CGU_ESR_10, 0x0); /* disable divider */
+ break;
+
+ case PORT_AI0:
+ cgu->clk_int_port[PORT_AI0] = 1;
+
+ SAA716x_EPWR(CGU, CGU_FS1_11, 0x8); /* AI 0 clk */
+ SAA716x_EPWR(CGU, CGU_ESR_11, 0x0); /* disable divider */
+ break;
+
+ case PORT_AI1:
+ cgu->clk_int_port[PORT_AI1] = 1;
+
+ SAA716x_EPWR(CGU, CGU_FS1_12, 0x9); /* AI 1 clk */
+ SAA716x_EPWR(CGU, CGU_ESR_12, 0x0); /* disable divider */
+ break;
+
+ default:
+ dprintk(SAA716x_ERROR, 1, "Unknown port <%02x>", port);
+ delay = 0;
+ break;
+
+ }
+
+ if (delay)
+ msleep(1);
+
+ return 0;
+}
+
+int saa716x_get_clk(struct saa716x_dev *saa716x,
+ enum saa716x_clk_domain domain,
+ u32 *frequency)
+{
+ struct saa716x_cgu *cgu = &saa716x->cgu;
+
+ switch (domain) {
+ case CLK_DOMAIN_PSS:
+ case CLK_DOMAIN_DCS:
+ case CLK_DOMAIN_SPI:
+ case CLK_DOMAIN_I2C:
+ case CLK_DOMAIN_PHI:
+ case CLK_DOMAIN_VI0:
+ case CLK_DOMAIN_VI1:
+ case CLK_DOMAIN_FGPI0:
+ case CLK_DOMAIN_FGPI1:
+ case CLK_DOMAIN_FGPI2:
+ case CLK_DOMAIN_FGPI3:
+ case CLK_DOMAIN_AI0:
+ case CLK_DOMAIN_AI1:
+ case CLK_DOMAIN_PHY:
+ *frequency = cgu->clk_freq[domain];
+ break;
+
+ case CLK_DOMAIN_VI0VBI:
+ *frequency = cgu->clk_freq[CLK_DOMAIN_VI0];
+ break;
+
+ case CLK_DOMAIN_VI1VBI:
+ *frequency =cgu->clk_freq[CLK_DOMAIN_VI1];
+ break;
+ default:
+ dprintk(SAA716x_ERROR, 1, "Error Clock domain <%02x>", domain);
+ break;
+ }
+
+ return 0;
+}
+
+int saa716x_set_clk(struct saa716x_dev *saa716x,
+ enum saa716x_clk_domain domain,
+ u32 frequency)
+{
+ struct saa716x_cgu *cgu = &saa716x->cgu;
+
+ u32 M = 1, N = 1, reset, i;
+ s8 N_tmp, M_tmp, sub, add, lsb;
+
+
+ if (cgu->clk_freq_min > frequency)
+ frequency = cgu->clk_freq_min;
+
+ if (cgu->clk_freq_max < frequency)
+ frequency = cgu->clk_freq_max;
+
+ switch (domain) {
+ case CLK_DOMAIN_PSS:
+ case CLK_DOMAIN_DCS:
+ case CLK_DOMAIN_SPI:
+ case CLK_DOMAIN_I2C:
+ case CLK_DOMAIN_PHI:
+ case CLK_DOMAIN_FGPI0:
+ case CLK_DOMAIN_FGPI1:
+ case CLK_DOMAIN_FGPI2:
+ case CLK_DOMAIN_FGPI3:
+ case CLK_DOMAIN_AI0:
+ case CLK_DOMAIN_AI1:
+ case CLK_DOMAIN_PHY:
+
+ if (frequency == cgu->clk_freq[domain])
+ return 0; /* same frequency */
+ break;
+
+ case CLK_DOMAIN_VI0:
+
+ if (frequency == cgu->clk_vi_0[1]) {
+ return 0;
+
+ } else if (frequency == cgu->clk_vi_0[0]) {
+ cgu->clk_vi_0[1] = frequency; /* store */
+
+ if (frequency == cgu->clk_vi_0[2])
+ return 0;
+
+ } else {
+ cgu->clk_vi_0[1] = frequency;
+
+ if (frequency != cgu->clk_vi_0[2])
+ return 0;
+
+ }
+ break;
+
+ case CLK_DOMAIN_VI1:
+ if (frequency == cgu->clk_vi_1[1]) {
+ return 0;
+
+ } else if (frequency == cgu->clk_vi_1[0]) {
+ cgu->clk_vi_1[1] = frequency; /* store */
+
+ if (frequency == cgu->clk_vi_1[2])
+ return 0;
+
+ } else {
+ cgu->clk_vi_1[1] = frequency;
+
+ if (frequency != cgu->clk_vi_1[2])
+ return 0;
+
+ }
+ break;
+
+ case CLK_DOMAIN_VI0VBI:
+ if (frequency == cgu->clk_vi_0[2]) {
+ return 0;
+
+ } else if (frequency == cgu->clk_vi_0[0]) {
+ cgu->clk_vi_0[2] = frequency; /* store */
+
+ if (frequency == cgu->clk_vi_0[1])
+ return 0;
+
+ } else {
+ cgu->clk_vi_0[2] = frequency; /* store */
+
+ if (frequency != cgu->clk_vi_0[1])
+ return 0;
+
+ }
+ domain = CLK_DOMAIN_VI0; /* change domain */
+ break;
+
+ case CLK_DOMAIN_VI1VBI:
+ if (frequency == cgu->clk_vi_1[2]) {
+ return 0;
+
+ } else if (frequency == cgu->clk_vi_1[0]) {
+ cgu->clk_vi_1[2] = frequency; /* store */
+
+ if (frequency == cgu->clk_vi_1[1])
+ return 0;
+
+ } else {
+ cgu->clk_vi_1[2] = frequency; /* store */
+
+ if (frequency != cgu->clk_vi_1[1])
+ return 0;
+
+ }
+ domain = CLK_DOMAIN_VI1; /* change domain */
+ break;
+ }
+
+ /* calculate divider */
+ do {
+ M = (N * PLL_FREQ) / frequency;
+ if (M == 0)
+ N++;
+
+ } while (M == 0);
+
+ /* calculate frequency */
+ cgu->clk_freq[domain] = (N * PLL_FREQ) / M;
+
+ N_tmp = N & 0xff;
+ M_tmp = M & 0xff;
+ sub = -N_tmp;
+ add = M_tmp - N_tmp;
+ lsb = 4; /* run */
+
+ if (((10 * N) / M) < 5)
+ lsb |= 1; /* stretch */
+
+ /* store new divider */
+ cgu->clk_curr_div[domain] = sub & 0xff;
+ cgu->clk_curr_div[domain] <<= 8;
+ cgu->clk_curr_div[domain] = add & 0xff;
+ cgu->clk_curr_div[domain] <<= 3;
+ cgu->clk_curr_div[domain] |= lsb;
+
+ dprintk(SAA716x_DEBUG, 1, "Domain <0x%02x> Frequency <%d> Set Freq <%d> N=%d M=%d Divider <0x%02x>",
+ domain,
+ frequency,
+ cgu->clk_freq[domain],
+ N,
+ M,
+ cgu->clk_curr_div[domain]);
+
+ reset = 0;
+
+ /* Reset */
+ SAA716x_EPWR(CGU, cgu_clk[domain], cgu->clk_curr_div[domain] | 0x2);
+
+ /* Reset disable */
+ for (i = 0; i < 1000; i++) {
+ msleep(10);
+ reset = SAA716x_EPRD(CGU, cgu_clk[domain]);
+
+ if (cgu->clk_curr_div[domain == reset])
+ break;
+ }
+
+ if (cgu->clk_curr_div[domain] != reset)
+ SAA716x_EPWR(CGU, cgu_clk[domain], cgu->clk_curr_div[domain]);
+
+ return 0;
+}
+
+int saa716x_cgu_init(struct saa716x_dev *saa716x)
+{
+ struct saa716x_cgu *cgu = &saa716x->cgu;
+
+ cgu->clk_freq_min = PLL_FREQ / 255;
+ if (PLL_FREQ > (cgu->clk_freq_min * 255))
+ cgu->clk_freq_min++;
+
+ cgu->clk_freq_max = PLL_FREQ;
+
+ saa716x_getbootscript_setup(saa716x);
+ saa716x_set_clk_internal(saa716x, PORT_ALL);
+
+ return 0;
+}
+EXPORT_SYMBOL(saa716x_cgu_init);
diff --git a/drivers/media/common/saa716x/saa716x_cgu.h b/drivers/media/common/saa716x/saa716x_cgu.h
new file mode 100644
index 0000000..5353cf2
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_cgu.h
@@ -0,0 +1,61 @@
+#ifndef __SAA716x_CGU_H
+#define __SAA716x_CGU_H
+
+#define PLL_FREQ 2500
+
+#define SAA716x_CGU_CLKRUN(__reg) do { \
+ SAA716x_EPWR(CGU, CGU_PCR_##__reg, CGU_PCR_RUN); /* Run */ \
+ SAA716x_EPWR(CGU, CGU_SCR_##__reg, CGU_SCR_ENF1); /* Switch */ \
+ SAA716x_EPWR(CGU, CGU_FS1_##__reg, 0x00000000); /* PLL Clk */ \
+ SAA716x_EPWR(CGU, CGU_ESR_##__reg, CGU_ESR_FD_EN); /* Frac div */ \
+} while (0)
+
+enum saa716x_clk_domain {
+ CLK_DOMAIN_PSS = 0,
+ CLK_DOMAIN_DCS = 1,
+ CLK_DOMAIN_SPI = 2,
+ CLK_DOMAIN_I2C = 3,
+ CLK_DOMAIN_PHI = 4,
+ CLK_DOMAIN_VI0 = 5,
+ CLK_DOMAIN_VI1 = 6,
+ CLK_DOMAIN_FGPI0 = 7,
+ CLK_DOMAIN_FGPI1 = 8,
+ CLK_DOMAIN_FGPI2 = 9,
+ CLK_DOMAIN_FGPI3 = 10,
+ CLK_DOMAIN_AI0 = 11,
+ CLK_DOMAIN_AI1 = 12,
+ CLK_DOMAIN_PHY = 13,
+ CLK_DOMAIN_VI0VBI = 14,
+ CLK_DOMAIN_VI1VBI = 15
+};
+
+#define PORT_VI0_VIDEO 0
+#define PORT_VI0_VBI 2
+#define PORT_VI1_VIDEO 3
+#define PORT_VI1_VBI 5
+#define PORT_FGPI0 6
+#define PORT_FGPI1 7
+#define PORT_FGPI2 8
+#define PORT_FGPI3 9
+#define PORT_AI0 10
+#define PORT_AI1 11
+#define PORT_ALL 12
+
+#define CGU_CLKS 14
+
+struct saa716x_cgu {
+ u8 clk_int_port[12];
+ u32 clk_vi_0[3];
+ u32 clk_vi_1[3];
+ u32 clk_boot_div[CGU_CLKS];
+ u32 clk_curr_div[CGU_CLKS];
+ u32 clk_freq[CGU_CLKS];
+ u32 clk_freq_min;
+ u32 clk_freq_max;
+};
+
+extern int saa716x_cgu_init(struct saa716x_dev *saa716x);
+extern int saa716x_set_clk_internal(struct saa716x_dev *saa716x, u32 port);
+extern int saa716x_set_clk_external(struct saa716x_dev *saa716x, u32 port);
+
+#endif /* __SAA716x_CGU_H */
diff --git a/drivers/media/common/saa716x/saa716x_cgu_reg.h b/drivers/media/common/saa716x/saa716x_cgu_reg.h
new file mode 100644
index 0000000..f7d82ae
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_cgu_reg.h
@@ -0,0 +1,178 @@
+#ifndef __SAA716x_CGU_REG_H
+#define __SAA716x_CGU_REG_H
+
+/* -------------- CGU Registers -------------- */
+
+#define CGU_SCR_0 0x000
+#define CGU_SCR_1 0x004
+#define CGU_SCR_2 0x008
+#define CGU_SCR_3 0x00c
+#define CGU_SCR_4 0x010
+#define CGU_SCR_5 0x014
+#define CGU_SCR_6 0x018
+#define CGU_SCR_7 0x01c
+#define CGU_SCR_8 0x020
+#define CGU_SCR_9 0x024
+#define CGU_SCR_10 0x028
+#define CGU_SCR_11 0x02c
+#define CGU_SCR_12 0x030
+#define CGU_SCR_13 0x034
+#define CGU_SCR_STOP (0x00000001 << 3)
+#define CGU_SCR_RESET (0x00000001 << 2)
+#define CGU_SCR_ENF2 (0x00000001 << 1)
+#define CGU_SCR_ENF1 (0x00000001 << 0)
+
+#define CGU_FS1_0 0x038
+#define CGU_FS1_1 0x03c
+#define CGU_FS1_2 0x040
+#define CGU_FS1_3 0x044
+#define CGU_FS1_4 0x048
+#define CGU_FS1_5 0x04c
+#define CGU_FS1_6 0x050
+#define CGU_FS1_7 0x054
+#define CGU_FS1_8 0x058
+#define CGU_FS1_9 0x05c
+#define CGU_FS1_10 0x060
+#define CGU_FS1_11 0x064
+#define CGU_FS1_12 0x068
+#define CGU_FS1_13 0x06c
+#define CGU_FS1_PLL (0x00000000 << 0)
+
+
+#define CGU_FS2_0 0x070
+#define CGU_FS2_1 0x074
+#define CGU_FS2_2 0x078
+#define CGU_FS2_3 0x07c
+#define CGU_FS2_4 0x080
+#define CGU_FS2_5 0x084
+#define CGU_FS2_6 0x088
+#define CGU_FS2_7 0x08c
+#define CGU_FS2_8 0x090
+#define CGU_FS2_9 0x094
+#define CGU_FS2_10 0x098
+#define CGU_FS2_11 0x09c
+#define CGU_FS2_12 0x0a0
+#define CGU_FS2_13 0x0a4
+
+#define CGU_SSR_0 0x0a8
+#define CGU_SSR_1 0x0ac
+#define CGU_SSR_2 0x0b0
+#define CGU_SSR_3 0x0b4
+#define CGU_SSR_4 0x0b8
+#define CGU_SSR_5 0x0bc
+#define CGU_SSR_6 0x0c0
+#define CGU_SSR_7 0x0c4
+#define CGU_SSR_8 0x0c8
+#define CGU_SSR_9 0x0cc
+#define CGU_SSR_10 0x0d0
+#define CGU_SSR_11 0x0d4
+#define CGU_SSR_12 0x0d8
+#define CGU_SSR_13 0x0dc
+
+#define CGU_PCR_0_0 0x0e0
+#define CGU_PCR_0_1 0x0e4
+#define CGU_PCR_0_2 0x0e8
+#define CGU_PCR_0_3 0x0ec
+#define CGU_PCR_0_4 0x0f0
+#define CGU_PCR_0_5 0x0f4
+#define CGU_PCR_0_6 0x0f8
+#define CGU_PCR_0_7 0x0fc
+#define CGU_PCR_1_0 0x100
+#define CGU_PCR_1_1 0x104
+#define CGU_PCR_2_0 0x108
+#define CGU_PCR_2_1 0x10c
+#define CGU_PCR_3_0 0x110
+#define CGU_PCR_3_1 0x114
+#define CGU_PCR_3_2 0x118
+#define CGU_PCR_4_0 0x11c
+#define CGU_PCR_4_1 0x120
+#define CGU_PCR_5 0x124
+#define CGU_PCR_6 0x128
+#define CGU_PCR_7 0x12c
+#define CGU_PCR_8 0x130
+#define CGU_PCR_9 0x134
+#define CGU_PCR_10 0x138
+#define CGU_PCR_11 0x13c
+#define CGU_PCR_12 0x140
+#define CGU_PCR_13 0x144
+#define CGU_PCR_WAKE_EN (0x00000001 << 2)
+#define CGU_PCR_AUTO (0x00000001 << 1)
+#define CGU_PCR_RUN (0x00000001 << 0)
+
+
+#define CGU_PSR_0_0 0x148
+#define CGU_PSR_0_1 0x14c
+#define CGU_PSR_0_2 0x150
+#define CGU_PSR_0_3 0x154
+#define CGU_PSR_0_4 0x158
+#define CGU_PSR_0_5 0x15c
+#define CGU_PSR_0_6 0x160
+#define CGU_PSR_0_7 0x164
+#define CGU_PSR_1_0 0x168
+#define CGU_PSR_1_1 0x16c
+#define CGU_PSR_2_0 0x170
+#define CGU_PSR_2_1 0x174
+#define CGU_PSR_3_0 0x178
+#define CGU_PSR_3_1 0x17c
+#define CGU_PSR_3_2 0x180
+#define CGU_PSR_4_0 0x184
+#define CGU_PSR_4_1 0x188
+#define CGU_PSR_5 0x18c
+#define CGU_PSR_6 0x190
+#define CGU_PSR_7 0x194
+#define CGU_PSR_8 0x198
+#define CGU_PSR_9 0x19c
+#define CGU_PSR_10 0x1a0
+#define CGU_PSR_11 0x1a4
+#define CGU_PSR_12 0x1a8
+#define CGU_PSR_13 0x1ac
+
+#define CGU_ESR_0_0 0x1b0
+#define CGU_ESR_0_1 0x1b4
+#define CGU_ESR_0_2 0x1b8
+#define CGU_ESR_0_3 0x1bc
+#define CGU_ESR_0_4 0x1c0
+#define CGU_ESR_0_5 0x1c4
+#define CGU_ESR_0_6 0x1c8
+#define CGU_ESR_0_7 0x1cc
+#define CGU_ESR_1_0 0x1d0
+#define CGU_ESR_1_1 0x1d4
+#define CGU_ESR_2_0 0x1d8
+#define CGU_ESR_2_1 0x1dc
+#define CGU_ESR_3_0 0x1e0
+#define CGU_ESR_3_1 0x1e4
+#define CGU_ESR_3_2 0x1e8
+#define CGU_ESR_4_0 0x1ec
+#define CGU_ESR_4_1 0x1f0
+#define CGU_ESR_5 0x1f4
+#define CGU_ESR_6 0x1f8
+#define CGU_ESR_7 0x1fc
+#define CGU_ESR_8 0x200
+#define CGU_ESR_9 0x204
+#define CGU_ESR_10 0x208
+#define CGU_ESR_11 0x20c
+#define CGU_ESR_12 0x210
+#define CGU_ESR_13 0x214
+#define CGU_ESR_FD_EN (0x00000001 << 0)
+
+#define CGU_FDC_0 0x218
+#define CGU_FDC_1 0x21c
+#define CGU_FDC_2 0x220
+#define CGU_FDC_3 0x224
+#define CGU_FDC_4 0x228
+#define CGU_FDC_5 0x22c
+#define CGU_FDC_6 0x230
+#define CGU_FDC_7 0x234
+#define CGU_FDC_8 0x238
+#define CGU_FDC_9 0x23c
+#define CGU_FDC_10 0x240
+#define CGU_FDC_11 0x244
+#define CGU_FDC_12 0x248
+#define CGU_FDC_13 0x24c
+#define CGU_FDC_STRETCH (0x00000001 << 0)
+#define CGU_FDC_RESET (0x00000001 << 1)
+#define CGU_FDC_RUN1 (0x00000001 << 2)
+#define CGU_FDC_MADD (0x000000ff << 3)
+#define CGU_FDC_MSUB (0x000000ff << 11)
+
+#endif /* __SAA716x_CGU_REG_H */
diff --git a/drivers/media/common/saa716x/saa716x_dcs_reg.h b/drivers/media/common/saa716x/saa716x_dcs_reg.h
new file mode 100644
index 0000000..26dba68
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_dcs_reg.h
@@ -0,0 +1,56 @@
+#ifndef __SAA716x_DCS_REG_H
+#define __SAA716x_DCS_REG_H
+
+/* -------------- DCS Registers -------------- */
+
+#define DCSC_CTRL 0x000
+#define DCSC_SEL_PLLDI (0x03ffffff << 5)
+#define DCSC_TOUT_SEL (0x0000000f << 1)
+#define DCSC_TOUT_OFF (0x00000001 << 0)
+
+#define DCSC_ADDR 0x00c
+#define DCSC_ERR_TOUT_ADDR (0x3fffffff << 2)
+
+#define DCSC_STAT 0x010
+#define DCSC_ERR_TOUT_GNT (0x0000001f << 24)
+#define DCSC_ERR_TOUT_SEL (0x0000007f << 10)
+#define DCSC_ERR_TOUT_READ (0x00000001 << 8)
+#define DCSC_ERR_TOUT_MASK (0x0000000f << 4)
+#define DCSC_ERR_ACK (0x00000001 << 1)
+
+#define DCSC_FEATURES 0x040
+#define DCSC_UNIQUE_ID (0x00000007 << 16)
+#define DCSC_SECURITY (0x00000001 << 14)
+#define DCSC_NUM_BASE_REGS (0x00000003 << 11)
+#define DCSC_NUM_TARGETS (0x0000001f << 5)
+#define DCSC_NUM_INITIATORS (0x0000001f << 0)
+
+#define DCSC_BASE_REG0 0x100
+#define DCSC_BASE_N_REG (0x00000fff << 20)
+
+#define DCSC_INT_CLR_ENABLE 0xfd8
+#define DCSC_INT_CLR_ENABLE_TOUT (0x00000001 << 1)
+#define DCSC_INT_CLR_ENABLE_ERROR (0x00000001 << 0)
+
+#define DCSC_INT_SET_ENABLE 0xfdc
+#define DCSC_INT_SET_ENABLE_TOUT (0x00000001 << 1)
+#define DCSC_INT_SET_ENABLE_ERROR (0x00000001 << 0)
+
+#define DCSC_INT_STATUS 0xfe0
+#define DCSC_INT_STATUS_TOUT (0x00000001 << 1)
+#define DCSC_INT_STATUS_ERROR (0x00000001 << 0)
+
+#define DCSC_INT_ENABLE 0xfe4
+#define DCSC_INT_ENABLE_TOUT (0x00000001 << 1)
+#define DCSC_INT_ENABLE_ERROR (0x00000001 << 0)
+
+#define DCSC_INT_CLR_STATUS 0xfe8
+#define DCSC_INT_CLEAR_TOUT (0x00000001 << 1)
+#define DCSC_INT_CLEAR_ERROR (0x00000001 << 0)
+
+#define DCSC_INT_SET_STATUS 0xfec
+#define DCSC_INT_SET_TOUT (0x00000001 << 1)
+#define DCSC_INT_SET_ERROR (0x00000001 << 0)
+
+
+#endif /* __SAA716x_DCS_REG_H */
diff --git a/drivers/media/common/saa716x/saa716x_dma.c b/drivers/media/common/saa716x/saa716x_dma.c
new file mode 100644
index 0000000..21d1dd8
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_dma.c
@@ -0,0 +1,306 @@
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/scatterlist.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include "saa716x_dma.h"
+#include "saa716x_spi.h"
+#include "saa716x_priv.h"
+
+/* Allocates one page of memory, which is stores the data of one
+ * 716x page table. The result gets stored in the passed DMA buffer
+ * structure.
+ */
+static int saa716x_allocate_ptable(struct saa716x_dmabuf *dmabuf)
+{
+ struct saa716x_dev *saa716x = dmabuf->saa716x;
+ struct pci_dev *pdev = saa716x->pdev;
+
+ dprintk(SAA716x_DEBUG, 1, "SG Page table allocate");
+ dmabuf->mem_ptab_virt = (void *) __get_free_page(GFP_KERNEL);
+
+ if (dmabuf->mem_ptab_virt == NULL) {
+ dprintk(SAA716x_ERROR, 1, "ERROR: Out of pages !");
+ return -ENOMEM;
+ }
+
+ dmabuf->mem_ptab_phys = dma_map_single(&pdev->dev,
+ dmabuf->mem_ptab_virt,
+ SAA716x_PAGE_SIZE,
+ DMA_TO_DEVICE);
+
+ if (dmabuf->mem_ptab_phys == 0) {
+ dprintk(SAA716x_ERROR, 1, "ERROR: map memory failed !");
+ return -ENOMEM;
+ }
+
+ BUG_ON(!(((unsigned long) dmabuf->mem_ptab_phys % SAA716x_PAGE_SIZE) == 0));
+
+ return 0;
+}
+
+static void saa716x_free_ptable(struct saa716x_dmabuf *dmabuf)
+{
+ struct saa716x_dev *saa716x = dmabuf->saa716x;
+ struct pci_dev *pdev = saa716x->pdev;
+
+ BUG_ON(dmabuf == NULL);
+ dprintk(SAA716x_DEBUG, 1, "SG Page table free");
+
+ /* free physical PCI memory */
+ if (dmabuf->mem_ptab_phys != 0) {
+ dma_unmap_single(&pdev->dev,
+ dmabuf->mem_ptab_phys,
+ SAA716x_PAGE_SIZE,
+ DMA_TO_DEVICE);
+
+ dmabuf->mem_ptab_phys = 0;
+ }
+
+ /* free kernel memory */
+ if (dmabuf->mem_ptab_virt != NULL) {
+ free_page((unsigned long) dmabuf->mem_ptab_virt);
+ dmabuf->mem_ptab_virt = NULL;
+ }
+}
+
+static void saa716x_dmabuf_sgfree(struct saa716x_dmabuf *dmabuf)
+{
+ struct saa716x_dev *saa716x = dmabuf->saa716x;
+
+ BUG_ON(dmabuf == NULL);
+ dprintk(SAA716x_DEBUG, 1, "SG free");
+
+ dmabuf->mem_virt = NULL;
+ if (dmabuf->mem_virt_noalign != NULL) {
+ if (dmabuf->dma_type == SAA716x_DMABUF_INT)
+ vfree(dmabuf->mem_virt_noalign);
+
+ dmabuf->mem_virt_noalign = NULL;
+ }
+
+ if (dmabuf->sg_list != NULL) {
+ kfree(dmabuf->sg_list);
+ dmabuf->sg_list = NULL;
+ }
+}
+
+/*
+ * Create a SG, when an allocated buffer is passed to it,
+ * otherwise the needed memory gets allocated by itself
+ */
+static int saa716x_dmabuf_sgalloc(struct saa716x_dmabuf *dmabuf, void *buf, int size)
+{
+ struct saa716x_dev *saa716x = dmabuf->saa716x;
+ struct scatterlist *list;
+ struct page *pg;
+
+ int i, pages;
+
+ BUG_ON(!(size > 0));
+ BUG_ON(dmabuf == NULL);
+ dprintk(SAA716x_DEBUG, 1, "SG allocate");
+
+ if ((size % SAA716x_PAGE_SIZE) != 0) /* calculate required pages */
+ pages = size / SAA716x_PAGE_SIZE + 1;
+ else
+ pages = size / SAA716x_PAGE_SIZE;
+
+ /* Allocate memory for SG list */
+ dmabuf->sg_list = kzalloc(sizeof (struct scatterlist) * pages, GFP_KERNEL);
+ if (dmabuf->sg_list == NULL) {
+ dprintk(SAA716x_ERROR, 1, "Failed to allocate memory for scatterlist.");
+ return -ENOMEM;
+ }
+
+ dprintk(SAA716x_DEBUG, 1, "Initializing SG table");
+ sg_init_table(dmabuf->sg_list, pages);
+
+ if (buf == NULL) {
+
+ /* allocate memory, unaligned */
+ dmabuf->mem_virt_noalign = vmalloc((pages + 1) * SAA716x_PAGE_SIZE);
+ if (dmabuf->mem_virt_noalign == NULL) {
+ dprintk(SAA716x_ERROR, 1, "Failed to allocate memory for buffer");
+ return -ENOMEM;
+ }
+
+ /* align memory to page */
+ dmabuf->mem_virt = (void *) PAGE_ALIGN (((unsigned long) dmabuf->mem_virt_noalign));
+
+ BUG_ON(!((((unsigned long) dmabuf->mem_virt) % SAA716x_PAGE_SIZE) == 0));
+ } else {
+ dmabuf->mem_virt = buf;
+ }
+
+ dmabuf->list_len = pages; /* scatterlist length */
+ list = dmabuf->sg_list;
+
+ dprintk(SAA716x_DEBUG, 1, "Allocating SG pages");
+ for (i = 0; i < pages; i++) {
+ if (buf == NULL)
+ pg = vmalloc_to_page(dmabuf->mem_virt + i * SAA716x_PAGE_SIZE);
+ else
+ pg = virt_to_page(dmabuf->mem_virt + i * SAA716x_PAGE_SIZE);
+
+ BUG_ON(pg == NULL);
+ sg_set_page(&list[i], pg, SAA716x_PAGE_SIZE, 0);
+ }
+
+ dprintk(SAA716x_DEBUG, 1, "Done!");
+ return 0;
+}
+
+/* Fill the "page table" page with the pointers to the specified SG buffer */
+static void saa716x_dmabuf_sgpagefill(struct saa716x_dmabuf *dmabuf, struct scatterlist *sg_list, int pages, int offset)
+{
+ struct saa716x_dev *saa716x = dmabuf->saa716x;
+ struct pci_dev *pdev = saa716x->pdev;
+ struct scatterlist *sg_cur;
+
+ u32 *page;
+ int i, j, k = 0;
+ dma_addr_t addr = 0;
+
+ BUG_ON(dmabuf == NULL);
+ BUG_ON(sg_list == NULL);
+ BUG_ON(pages == 0);
+ dprintk(SAA716x_DEBUG, 1, "SG page fill");
+
+ /* make page writable for the PC */
+ dma_sync_single_for_cpu(&pdev->dev, dmabuf->mem_ptab_phys, SAA716x_PAGE_SIZE, DMA_TO_DEVICE);
+ page = dmabuf->mem_ptab_virt;
+
+ /* create page table */
+ for (i = 0; i < pages; i++) {
+ sg_cur = &sg_list[i];
+ BUG_ON(!(((sg_cur->length + sg_cur->offset) % SAA716x_PAGE_SIZE) == 0));
+
+ if (i == 0)
+ dmabuf->offset = (sg_cur->length + sg_cur->offset) % SAA716x_PAGE_SIZE;
+ else
+ BUG_ON(sg_cur->offset != 0);
+
+ for (j = 0; (j * SAA716x_PAGE_SIZE) < sg_dma_len(sg_cur); j++) {
+
+ if ((offset + sg_cur->offset) >= SAA716x_PAGE_SIZE) {
+ offset -= SAA716x_PAGE_SIZE;
+ continue;
+ }
+
+ addr = ((u64)sg_dma_address(sg_cur)) + (j * SAA716x_PAGE_SIZE) - sg_cur->offset;
+
+ BUG_ON(addr == 0);
+ page[k * 2] = (u32 )addr; /* Low */
+ page[k * 2 + 1] = (u32 )(((u64) addr) >> 32); /* High */
+ BUG_ON(page[k * 2] % SAA716x_PAGE_SIZE);
+ k++;
+ }
+ }
+
+ for (; k < (SAA716x_PAGE_SIZE / 8); k++) {
+ page[k * 2] = (u32 ) addr;
+ page[k * 2 + 1] = (u32 ) (((u64 ) addr) >> 32);
+ }
+
+ /* make "page table" page writable for the PC */
+ dma_sync_single_for_device(&pdev->dev,
+ dmabuf->mem_ptab_phys,
+ SAA716x_PAGE_SIZE,
+ DMA_TO_DEVICE);
+
+}
+
+void saa716x_dmabufsync_dev(struct saa716x_dmabuf *dmabuf)
+{
+ struct saa716x_dev *saa716x = dmabuf->saa716x;
+ struct pci_dev *pdev = saa716x->pdev;
+
+ dprintk(SAA716x_DEBUG, 1, "DMABUF sync DEVICE");
+ BUG_ON(dmabuf->sg_list == NULL);
+
+ dma_sync_sg_for_device(&pdev->dev,
+ dmabuf->sg_list,
+ dmabuf->list_len,
+ DMA_FROM_DEVICE);
+
+}
+
+void saa716x_dmabufsync_cpu(struct saa716x_dmabuf *dmabuf)
+{
+ struct saa716x_dev *saa716x = dmabuf->saa716x;
+ struct pci_dev *pdev = saa716x->pdev;
+
+ dprintk(SAA716x_DEBUG, 1, "DMABUF sync CPU");
+ BUG_ON(dmabuf->sg_list == NULL);
+
+ dma_sync_sg_for_cpu(&pdev->dev,
+ dmabuf->sg_list,
+ dmabuf->list_len,
+ DMA_FROM_DEVICE);
+}
+
+/* Allocates a DMA buffer for the specified external linear buffer. */
+int saa716x_dmabuf_alloc(struct saa716x_dev *saa716x, struct saa716x_dmabuf *dmabuf, int size)
+{
+ struct pci_dev *pdev = saa716x->pdev;
+
+ int ret;
+
+ BUG_ON(saa716x == NULL);
+ BUG_ON(dmabuf == NULL);
+ BUG_ON(! (size > 0));
+
+ dmabuf->dma_type = SAA716x_DMABUF_INT;
+
+ dmabuf->mem_virt_noalign = NULL;
+ dmabuf->mem_virt = NULL;
+ dmabuf->mem_ptab_phys = 0;
+ dmabuf->mem_ptab_virt = NULL;
+
+ dmabuf->list_len = 0;
+ dmabuf->saa716x = saa716x;
+
+ /* Allocate page table */
+ ret = saa716x_allocate_ptable(dmabuf);
+ if (ret < 0) {
+ dprintk(SAA716x_ERROR, 1, "PT alloc failed, Out of memory");
+ goto err1;
+ }
+
+ /* Allocate buffer as SG */
+ ret = saa716x_dmabuf_sgalloc(dmabuf, NULL, size);
+ if (ret < 0) {
+ dprintk(SAA716x_ERROR, 1, "SG alloc failed");
+ goto err2;
+ }
+
+ ret = dma_map_sg(&pdev->dev, dmabuf->sg_list, dmabuf->list_len, DMA_FROM_DEVICE);
+ if (ret < 0) {
+ dprintk(SAA716x_ERROR, 1, "SG map failed");
+ goto err3;
+ }
+
+ saa716x_dmabuf_sgpagefill(dmabuf, dmabuf->sg_list, ret, 0);
+
+ return 0;
+err3:
+ saa716x_dmabuf_sgfree(dmabuf);
+err2:
+ saa716x_free_ptable(dmabuf);
+err1:
+ return ret;
+}
+
+void saa716x_dmabuf_free(struct saa716x_dev *saa716x, struct saa716x_dmabuf *dmabuf)
+{
+ struct pci_dev *pdev = saa716x->pdev;
+
+ BUG_ON(saa716x == NULL);
+ BUG_ON(dmabuf == NULL);
+
+ dma_unmap_sg(&pdev->dev, dmabuf->sg_list, dmabuf->list_len, DMA_FROM_DEVICE);
+ saa716x_dmabuf_sgfree(dmabuf);
+ saa716x_free_ptable(dmabuf);
+}
diff --git a/drivers/media/common/saa716x/saa716x_dma.h b/drivers/media/common/saa716x/saa716x_dma.h
new file mode 100644
index 0000000..f92d667
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_dma.h
@@ -0,0 +1,38 @@
+#ifndef __SAA716x_DMA_H
+#define __SAA716x_DMA_H
+
+#define SAA716x_PAGE_SIZE 4096
+
+enum saa716x_dma_type {
+ SAA716x_DMABUF_EXT_LIN, /* Linear external */
+ SAA716x_DMABUF_EXT_SG, /* SG external */
+ SAA716x_DMABUF_INT /* Linear internal */
+};
+
+struct saa716x_dev;
+
+struct saa716x_dmabuf {
+ enum saa716x_dma_type dma_type;
+
+ void *mem_virt_noalign;
+ void *mem_virt; /* page aligned */
+ dma_addr_t mem_ptab_phys;
+ void *mem_ptab_virt;
+ void *sg_list; /* SG list */
+
+ struct saa716x_dev *saa716x;
+
+ int list_len; /* buffer len */
+ int offset; /* page offset */
+};
+
+extern int saa716x_dmabuf_alloc(struct saa716x_dev *saa716x,
+ struct saa716x_dmabuf *dmabuf,
+ int size);
+extern void saa716x_dmabuf_free(struct saa716x_dev *saa716x,
+ struct saa716x_dmabuf *dmabuf);
+
+extern void saa716x_dmabufsync_dev(struct saa716x_dmabuf *dmabuf);
+extern void saa716x_dmabufsync_cpu(struct saa716x_dmabuf *dmabuf);
+
+#endif /* __SAA716x_DMA_H */
diff --git a/drivers/media/common/saa716x/saa716x_dma_reg.h b/drivers/media/common/saa716x/saa716x_dma_reg.h
new file mode 100644
index 0000000..6037ca9
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_dma_reg.h
@@ -0,0 +1,200 @@
+#ifndef __SAA716x_DMA_REG_H
+#define __SAA716x_DMA_REG_H
+
+/* -------------- BAM Registers -------------- */
+
+#define BAM_VI0_0_DMA_BUF_MODE 0x000
+
+#define BAM_VI0_0_ADDR_OFFST_0 0x004
+#define BAM_VI0_0_ADDR_OFFST_1 0x008
+#define BAM_VI0_0_ADDR_OFFST_2 0x00c
+#define BAM_VI0_0_ADDR_OFFST_3 0x010
+#define BAM_VI0_0_ADDR_OFFST_4 0x014
+#define BAM_VI0_0_ADDR_OFFST_5 0x018
+#define BAM_VI0_0_ADDR_OFFST_6 0x01c
+#define BAM_VI0_0_ADDR_OFFST_7 0x020
+
+#define BAM_VI0_1_DMA_BUF_MODE 0x024
+#define BAM_VI0_1_ADDR_OFFST_0 0x028
+#define BAM_VI0_1_ADDR_OFFST_1 0x02c
+#define BAM_VI0_1_ADDR_OFFST_2 0x030
+#define BAM_VI0_1_ADDR_OFFST_3 0x034
+#define BAM_VI0_1_ADDR_OFFST_4 0x038
+#define BAM_VI0_1_ADDR_OFFST_5 0x03c
+#define BAM_VI0_1_ADDR_OFFST_6 0x040
+#define BAM_VI0_1_ADDR_OFFST_7 0x044
+
+#define BAM_VI0_2_DMA_BUF_MODE 0x048
+#define BAM_VI0_2_ADDR_OFFST_0 0x04c
+#define BAM_VI0_2_ADDR_OFFST_1 0x050
+#define BAM_VI0_2_ADDR_OFFST_2 0x054
+#define BAM_VI0_2_ADDR_OFFST_3 0x058
+#define BAM_VI0_2_ADDR_OFFST_4 0x05c
+#define BAM_VI0_2_ADDR_OFFST_5 0x060
+#define BAM_VI0_2_ADDR_OFFST_6 0x064
+#define BAM_VI0_2_ADDR_OFFST_7 0x068
+
+
+#define BAM_VI1_0_DMA_BUF_MODE 0x06c
+#define BAM_VI1_0_ADDR_OFFST_0 0x070
+#define BAM_VI1_0_ADDR_OFFST_1 0x074
+#define BAM_VI1_0_ADDR_OFFST_2 0x078
+#define BAM_VI1_0_ADDR_OFFST_3 0x07c
+#define BAM_VI1_0_ADDR_OFFST_4 0x080
+#define BAM_VI1_0_ADDR_OFFST_5 0x084
+#define BAM_VI1_0_ADDR_OFFST_6 0x088
+#define BAM_VI1_0_ADDR_OFFST_7 0x08c
+
+#define BAM_VI1_1_DMA_BUF_MODE 0x090
+#define BAM_VI1_1_ADDR_OFFST_0 0x094
+#define BAM_VI1_1_ADDR_OFFST_1 0x098
+#define BAM_VI1_1_ADDR_OFFST_2 0x09c
+#define BAM_VI1_1_ADDR_OFFST_3 0x0a0
+#define BAM_VI1_1_ADDR_OFFST_4 0x0a4
+#define BAM_VI1_1_ADDR_OFFST_5 0x0a8
+#define BAM_VI1_1_ADDR_OFFST_6 0x0ac
+#define BAM_VI1_1_ADDR_OFFST_7 0x0b0
+
+#define BAM_VI1_2_DMA_BUF_MODE 0x0b4
+#define BAM_VI1_2_ADDR_OFFST_0 0x0b8
+#define BAM_VI1_2_ADDR_OFFST_1 0x0bc
+#define BAM_VI1_2_ADDR_OFFST_2 0x0c0
+#define BAM_VI1_2_ADDR_OFFST_3 0x0c4
+#define BAM_VI1_2_ADDR_OFFST_4 0x0c8
+#define BAM_VI1_2_ADDR_OFFST_5 0x0cc
+#define BAM_VI1_2_ADDR_OFFST_6 0x0d0
+#define BAM_VI1_2_ADDR_OFFST_7 0x0d4
+
+
+#define BAM_FGPI0_DMA_BUF_MODE 0x0d8
+#define BAM_FGPI0_ADDR_OFFST_0 0x0dc
+#define BAM_FGPI0_ADDR_OFFST_1 0x0e0
+#define BAM_FGPI0_ADDR_OFFST_2 0x0e4
+#define BAM_FGPI0_ADDR_OFFST_3 0x0e8
+#define BAM_FGPI0_ADDR_OFFST_4 0x0ec
+#define BAM_FGPI0_ADDR_OFFST_5 0x0f0
+#define BAM_FGPI0_ADDR_OFFST_6 0x0f4
+#define BAM_FGPI0_ADDR_OFFST_7 0x0f8
+
+#define BAM_FGPI1_DMA_BUF_MODE 0x0fc
+#define BAM_FGPI1_ADDR_OFFST_0 0x100
+#define BAM_FGPI1_ADDR_OFFST_1 0x104
+#define BAM_FGPI1_ADDR_OFFST_2 0x108
+#define BAM_FGPI1_ADDR_OFFST_3 0x10c
+#define BAM_FGPI1_ADDR_OFFST_4 0x110
+#define BAM_FGPI1_ADDR_OFFST_5 0x114
+#define BAM_FGPI1_ADDR_OFFST_6 0x118
+#define BAM_FGPI1_ADDR_OFFST_7 0x11c
+
+#define BAM_FGPI2_DMA_BUF_MODE 0x120
+#define BAM_FGPI2_ADDR_OFFST_0 0x124
+#define BAM_FGPI2_ADDR_OFFST_1 0x128
+#define BAM_FGPI2_ADDR_OFFST_2 0x12c
+#define BAM_FGPI2_ADDR_OFFST_3 0x130
+#define BAM_FGPI2_ADDR_OFFST_4 0x134
+#define BAM_FGPI2_ADDR_OFFST_5 0x138
+#define BAM_FGPI2_ADDR_OFFST_6 0x13c
+#define BAM_FGPI2_ADDR_OFFST_7 0x140
+
+#define BAM_FGPI3_DMA_BUF_MODE 0x144
+#define BAM_FGPI3_ADDR_OFFST_0 0x148
+#define BAM_FGPI3_ADDR_OFFST_1 0x14c
+#define BAM_FGPI3_ADDR_OFFST_2 0x150
+#define BAM_FGPI3_ADDR_OFFST_3 0x154
+#define BAM_FGPI3_ADDR_OFFST_4 0x158
+#define BAM_FGPI3_ADDR_OFFST_5 0x15c
+#define BAM_FGPI3_ADDR_OFFST_6 0x160
+#define BAM_FGPI3_ADDR_OFFST_7 0x164
+
+
+#define BAM_AI0_DMA_BUF_MODE 0x168
+#define BAM_AI0_ADDR_OFFST_0 0x16c
+#define BAM_AI0_ADDR_OFFST_1 0x170
+#define BAM_AI0_ADDR_OFFST_2 0x174
+#define BAM_AI0_ADDR_OFFST_3 0x178
+#define BAM_AI0_ADDR_OFFST_4 0x17c
+#define BAM_AIO_ADDR_OFFST_5 0x180
+#define BAM_AI0_ADDR_OFFST_6 0x184
+#define BAM_AIO_ADDR_OFFST_7 0x188
+
+#define BAM_AI1_DMA_BUF_MODE 0x18c
+#define BAM_AI1_ADDR_OFFST_0 0x190
+#define BAM_AI1_ADDR_OFFST_1 0x194
+#define BAM_AI1_ADDR_OFFST_2 0x198
+#define BAM_AI1_ADDR_OFFST_3 0x19c
+#define BAM_AI1_ADDR_OFFST_4 0x1a0
+#define BAM_AI1_ADDR_OFFST_5 0x1a4
+#define BAM_AI1_ADDR_OFFST_6 0x1a8
+#define BAM_AI1_ADDR_OFFST_7 0x1ac
+
+#define BAM_SW_RST 0xff0
+#define BAM_SW_RESET (0x00000001 << 0)
+
+
+
+
+
+/* -------------- MMU Registers -------------- */
+
+#define MMU_MODE 0x000
+
+#define MMU_DMA_CONFIG0 0x004
+#define MMU_DMA_CONFIG1 0x008
+#define MMU_DMA_CONFIG2 0x00c
+#define MMU_DMA_CONFIG3 0x010
+#define MMU_DMA_CONFIG4 0x014
+#define MMU_DMA_CONFIG5 0x018
+#define MMU_DMA_CONFIG6 0x01c
+#define MMU_DMA_CONFIG7 0x020
+#define MMU_DMA_CONFIG8 0x024
+#define MMU_DMA_CONFIG9 0x028
+#define MMU_DMA_CONFIG10 0x02c
+#define MMU_DMA_CONFIG11 0x030
+#define MMU_DMA_CONFIG12 0x034
+#define MMU_DMA_CONFIG13 0x038
+#define MMU_DMA_CONFIG14 0x03c
+#define MMU_DMA_CONFIG15 0x040
+
+#define MMU_SW_RST 0xff0
+#define MMU_SW_RESET (0x0001 << 0)
+
+#define MMU_PTA_BASE0 0x044 /* DMA 0 */
+#define MMU_PTA_BASE1 0x084 /* DMA 1 */
+#define MMU_PTA_BASE2 0x0c4 /* DMA 2 */
+#define MMU_PTA_BASE3 0x104 /* DMA 3 */
+#define MMU_PTA_BASE4 0x144 /* DMA 4 */
+#define MMU_PTA_BASE5 0x184 /* DMA 5 */
+#define MMU_PTA_BASE6 0x1c4 /* DMA 6 */
+#define MMU_PTA_BASE7 0x204 /* DMA 7 */
+#define MMU_PTA_BASE8 0x244 /* DMA 8 */
+#define MMU_PTA_BASE9 0x284 /* DMA 9 */
+#define MMU_PTA_BASE10 0x2c4 /* DMA 10 */
+#define MMU_PTA_BASE11 0x304 /* DMA 11 */
+#define MMU_PTA_BASE12 0x344 /* DMA 12 */
+#define MMU_PTA_BASE13 0x384 /* DMA 13 */
+#define MMU_PTA_BASE14 0x3c4 /* DMA 14 */
+#define MMU_PTA_BASE15 0x404 /* DMA 15 */
+
+#define MMU_PTA_BASE 0x044 /* DMA 0 */
+#define MMU_PTA_OFFSET 0x40
+
+#define PTA_BASE(__ch) (MMU_PTA_BASE + (MMU_PTA_OFFSET * __ch))
+
+#define MMU_PTA0_LSB(__ch) PTA_BASE(__ch) + 0x00
+#define MMU_PTA0_MSB(__ch) PTA_BASE(__ch) + 0x04
+#define MMU_PTA1_LSB(__ch) PTA_BASE(__ch) + 0x08
+#define MMU_PTA1_MSB(__ch) PTA_BASE(__ch) + 0x0c
+#define MMU_PTA2_LSB(__ch) PTA_BASE(__ch) + 0x10
+#define MMU_PTA2_MSB(__ch) PTA_BASE(__ch) + 0x14
+#define MMU_PTA3_LSB(__ch) PTA_BASE(__ch) + 0x18
+#define MMU_PTA3_MSB(__ch) PTA_BASE(__ch) + 0x1c
+#define MMU_PTA4_LSB(__ch) PTA_BASE(__ch) + 0x20
+#define MMU_PTA4_MSB(__ch) PTA_BASE(__ch) + 0x24
+#define MMU_PTA5_LSB(__ch) PTA_BASE(__ch) + 0x28
+#define MMU_PTA5_MSB(__ch) PTA_BASE(__ch) + 0x2c
+#define MMU_PTA6_LSB(__ch) PTA_BASE(__ch) + 0x30
+#define MMU_PTA6_MSB(__ch) PTA_BASE(__ch) + 0x34
+#define MMU_PTA7_LSB(__ch) PTA_BASE(__ch) + 0x38
+#define MMU_PTA7_MSB(__ch) PTA_BASE(__ch) + 0x3c
+
+#endif /* __SAA716x_DMA_REG_H */
diff --git a/drivers/media/common/saa716x/saa716x_ff.h b/drivers/media/common/saa716x/saa716x_ff.h
new file mode 100644
index 0000000..cb65929
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_ff.h
@@ -0,0 +1,158 @@
+#ifndef __SAA716x_FF_H
+#define __SAA716x_FF_H
+
+#include "dvb_filter.h"
+#include "dvb_ringbuffer.h"
+
+#define TECHNOTREND 0x13c2
+#define S2_6400_DUAL_S2_PREMIUM_DEVEL 0x3009
+#define S2_6400_DUAL_S2_PREMIUM_PROD 0x300A
+
+#define TT_PREMIUM_GPIO_POWER_ENABLE 27
+#define TT_PREMIUM_GPIO_RESET_BACKEND 26
+#define TT_PREMIUM_GPIO_FPGA_CS1 17
+#define TT_PREMIUM_GPIO_FPGA_CS0 16
+#define TT_PREMIUM_GPIO_FPGA_PROGRAMN 15
+#define TT_PREMIUM_GPIO_FPGA_DONE 14
+#define TT_PREMIUM_GPIO_FPGA_INITN 13
+
+/* fpga interrupt register addresses */
+#define FPGA_ADDR_PHI_ICTRL 0x8000 /* PHI General control of the PC => STB interrupt controller */
+#define FPGA_ADDR_PHI_ISR 0x8010 /* PHI Interrupt Status Register */
+#define FPGA_ADDR_PHI_ISET 0x8020 /* PHI Interrupt Set Register */
+#define FPGA_ADDR_PHI_ICLR 0x8030 /* PHI Interrupt Clear Register */
+#define FPGA_ADDR_EMI_ICTRL 0x8100 /* EMI General control of the STB => PC interrupt controller */
+#define FPGA_ADDR_EMI_ISR 0x8110 /* EMI Interrupt Status Register */
+#define FPGA_ADDR_EMI_ISET 0x8120 /* EMI Interrupt Set Register */
+#define FPGA_ADDR_EMI_ICLR 0x8130 /* EMI Interrupt Clear Register */
+
+/* fpga TS router register addresses */
+#define FPGA_ADDR_TSR_CTRL 0x8200 /* TS router control register */
+#define FPGA_ADDR_TSR_MUX1 0x8210 /* TS multiplexer 1 selection register */
+#define FPGA_ADDR_TSR_MUX2 0x8220 /* TS multiplexer 2 selection register */
+#define FPGA_ADDR_TSR_MUX3 0x8230 /* TS multiplexer 3 selection register */
+#define FPGA_ADDR_TSR_MUXCI1 0x8240 /* TS multiplexer CI 1 selection register */
+#define FPGA_ADDR_TSR_MUXCI2 0x8250 /* TS multiplexer CI 2 selection register */
+
+#define FPGA_ADDR_TSR_BRFE1 0x8280 /* bit rate for TS coming from frontend 1 */
+#define FPGA_ADDR_TSR_BRFE2 0x8284 /* bit rate for TS coming from frontend 2 */
+#define FPGA_ADDR_TSR_BRFF1 0x828C /* bit rate for TS coming from FIFO 1 */
+#define FPGA_ADDR_TSR_BRO1 0x8294 /* bit rate for TS going to output 1 */
+#define FPGA_ADDR_TSR_BRO2 0x8298 /* bit rate for TS going to output 2 */
+#define FPGA_ADDR_TSR_BRO3 0x829C /* bit rate for TS going to output 3 */
+
+/* fpga TS FIFO register addresses */
+#define FPGA_ADDR_FIFO_CTRL 0x8300 /* FIFO control register */
+#define FPGA_ADDR_FIFO_STAT 0x8310 /* FIFO status register */
+
+#define FPGA_ADDR_VERSION 0x80F0 /* FPGA bitstream version register */
+
+#define FPGA_ADDR_PIO_CTRL 0x8500 /* FPGA GPIO control register */
+
+#define ISR_CMD_MASK 0x0001 /* interrupt source for normal cmds (osd, fre, av, ...) */
+#define ISR_READY_MASK 0x0002 /* interrupt source for command acknowledge */
+#define ISR_BLOCK_MASK 0x0004 /* interrupt source for single block transfers and acknowledge */
+#define ISR_DATA_MASK 0x0008 /* interrupt source for data transfer acknowledge */
+#define ISR_BOOT_FINISH_MASK 0x0010 /* interrupt source for boot finish indication */
+#define ISR_AUDIO_PTS_MASK 0x0020 /* interrupt source for audio PTS */
+#define ISR_VIDEO_PTS_MASK 0x0040 /* interrupt source for video PTS */
+#define ISR_CURRENT_STC_MASK 0x0080 /* interrupt source for current system clock */
+#define ISR_REMOTE_EVENT_MASK 0x0100 /* interrupt source for remote events */
+#define ISR_DVO_FORMAT_MASK 0x0200 /* interrupt source for DVO format change */
+#define ISR_OSD_CMD_MASK 0x0400 /* interrupt source for OSD cmds */
+#define ISR_OSD_READY_MASK 0x0800 /* interrupt source for OSD command acknowledge */
+#define ISR_FE_CMD_MASK 0x1000 /* interrupt source for frontend cmds */
+#define ISR_FE_READY_MASK 0x2000 /* interrupt source for frontend command acknowledge */
+#define ISR_LOG_MESSAGE_MASK 0x4000 /* interrupt source for log messages */
+#define ISR_FIFO1_EMPTY_MASK 0x8000 /* interrupt source for FIFO1 empty */
+
+#define ADDR_CMD_DATA 0x0000 /* address for cmd data in fpga dpram */
+#define ADDR_OSD_CMD_DATA 0x01A0 /* address for OSD cmd data */
+#define ADDR_FE_CMD_DATA 0x05C0 /* address for frontend cmd data */
+#define ADDR_BLOCK_DATA 0x0600 /* address for block data */
+#define ADDR_AUDIO_PTS 0x3E00 /* address for audio PTS (64 Bits) */
+#define ADDR_VIDEO_PTS 0x3E08 /* address for video PTS (64 Bits) */
+#define ADDR_CURRENT_STC 0x3E10 /* address for system clock (64 Bits) */
+#define ADDR_DVO_FORMAT 0x3E18 /* address for DVO format 32 Bits) */
+#define ADDR_REMOTE_EVENT 0x3F00 /* address for remote events (32 Bits) */
+#define ADDR_LOG_MESSAGE 0x3F80 /* address for log messages */
+
+#define SIZE_CMD_DATA 0x01A0 /* maximum size for command data (416 Bytes) */
+#define SIZE_OSD_CMD_DATA 0x0420 /* maximum size for OSD command data (1056 Bytes) */
+#define SIZE_FE_CMD_DATA 0x0040 /* maximum size for frontend command data (64 Bytes) */
+#define SIZE_BLOCK_DATA 0x3800 /* maximum size for block data (14 kB) */
+#define SIZE_LOG_MESSAGE_DATA 0x0080 /* maximum size for log message data (128 Bytes) */
+
+#define SIZE_BLOCK_HEADER 8 /* block header size */
+
+#define MAX_RESULT_LEN 256
+#define MAX_DATA_LEN (1024 * 1024)
+
+#define TSOUT_LEN (1024 * TS_SIZE)
+#define TSBUF_LEN (8 * 1024)
+
+/* place to store all the necessary device information */
+struct sti7109_dev {
+ struct saa716x_dev *dev;
+ struct dvb_device *osd_dev;
+ struct dvb_device *video_dev;
+ struct dvb_device *audio_dev;
+
+ void *iobuf; /* memory for all buffers */
+ struct dvb_ringbuffer tsout; /* buffer for TS output */
+ u8 *tsbuf; /* temp ts buffer */
+
+ struct tasklet_struct fifo_tasklet;
+
+ wait_queue_head_t boot_finish_wq;
+ int boot_finished;
+
+ wait_queue_head_t cmd_ready_wq;
+ int cmd_ready;
+ u8 cmd_data[SIZE_CMD_DATA];
+ u32 cmd_len;
+
+ wait_queue_head_t result_avail_wq;
+ int result_avail;
+ u8 result_data[MAX_RESULT_LEN];
+ u32 result_len;
+ u32 result_max_len;
+
+ wait_queue_head_t osd_cmd_ready_wq;
+ int osd_cmd_ready;
+ u8 osd_cmd_data[SIZE_OSD_CMD_DATA];
+ u32 osd_cmd_len;
+
+ wait_queue_head_t osd_result_avail_wq;
+ int osd_result_avail;
+ u8 osd_result_data[MAX_RESULT_LEN];
+ u32 osd_result_len;
+ u32 osd_result_max_len;
+
+ u16 data_handle;
+ u8 *data_buffer; /* raw data transfer buffer */
+ wait_queue_head_t data_ready_wq;
+ int data_ready;
+ wait_queue_head_t block_done_wq;
+ int block_done;
+
+ struct mutex cmd_lock;
+ struct mutex osd_cmd_lock;
+ struct mutex data_lock;
+
+ u64 audio_pts;
+ u64 video_pts;
+ u64 current_stc;
+
+ u32 int_count_enable;
+ u32 total_int_count;
+ u32 fgpi_int_count[2];
+ u32 i2c_int_count[2];
+ u32 ext_int_total_count;
+ u32 ext_int_source_count[16];
+ u32 last_int_ticks;
+
+ u16 fpga_version;
+};
+
+#endif /* __SAA716x_FF_H */
diff --git a/drivers/media/common/saa716x/saa716x_ff_cmd.c b/drivers/media/common/saa716x/saa716x_ff_cmd.c
new file mode 100644
index 0000000..81c1078
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_ff_cmd.c
@@ -0,0 +1,412 @@
+#include <linux/types.h>
+
+#include <linux/dvb/video.h>
+#include <linux/dvb/osd.h>
+
+#include "saa716x_phi_reg.h"
+
+#include "saa716x_phi.h"
+#include "saa716x_spi.h"
+#include "saa716x_priv.h"
+#include "saa716x_ff.h"
+#include "saa716x_ff_cmd.h"
+
+
+int sti7109_cmd_init(struct sti7109_dev *sti7109)
+{
+ mutex_init(&sti7109->cmd_lock);
+ mutex_init(&sti7109->osd_cmd_lock);
+ mutex_init(&sti7109->data_lock);
+
+ init_waitqueue_head(&sti7109->boot_finish_wq);
+ sti7109->boot_finished = 0;
+
+ init_waitqueue_head(&sti7109->cmd_ready_wq);
+ sti7109->cmd_ready = 0;
+
+ init_waitqueue_head(&sti7109->result_avail_wq);
+ sti7109->result_avail = 0;
+
+ init_waitqueue_head(&sti7109->osd_cmd_ready_wq);
+ sti7109->osd_cmd_ready = 0;
+ init_waitqueue_head(&sti7109->osd_result_avail_wq);
+ sti7109->osd_result_avail = 0;
+
+ sti7109->data_handle = 0;
+ sti7109->data_buffer = (u8 *) (sti7109->iobuf + TSOUT_LEN + TSBUF_LEN);
+ init_waitqueue_head(&sti7109->data_ready_wq);
+ sti7109->data_ready = 0;
+ init_waitqueue_head(&sti7109->block_done_wq);
+ sti7109->block_done = 0;
+ return 0;
+}
+
+static int sti7109_do_raw_cmd(struct sti7109_dev * sti7109)
+{
+ struct saa716x_dev * saa716x = sti7109->dev;
+ unsigned long timeout;
+
+ timeout = 1 * HZ;
+ timeout = wait_event_interruptible_timeout(sti7109->cmd_ready_wq,
+ sti7109->cmd_ready == 1,
+ timeout);
+
+ if (timeout == -ERESTARTSYS || sti7109->cmd_ready == 0) {
+ if (timeout == -ERESTARTSYS) {
+ /* a signal arrived */
+ dprintk(SAA716x_ERROR, 1, "cmd ERESTARTSYS");
+ return -ERESTARTSYS;
+ }
+ dprintk(SAA716x_ERROR, 1,
+ "timed out waiting for command ready");
+ return -EIO;
+ }
+
+ sti7109->cmd_ready = 0;
+ sti7109->result_avail = 0;
+ saa716x_phi_write(saa716x, ADDR_CMD_DATA, sti7109->cmd_data,
+ sti7109->cmd_len);
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_PHI_ISET, ISR_CMD_MASK);
+
+ if (sti7109->result_max_len > 0) {
+ timeout = 1 * HZ;
+ timeout = wait_event_interruptible_timeout(
+ sti7109->result_avail_wq,
+ sti7109->result_avail == 1,
+ timeout);
+
+ if (timeout == -ERESTARTSYS || sti7109->result_avail == 0) {
+ sti7109->result_len = 0;
+ if (timeout == -ERESTARTSYS) {
+ /* a signal arrived */
+ dprintk(SAA716x_ERROR, 1, "result ERESTARTSYS");
+ return -ERESTARTSYS;
+ }
+ dprintk(SAA716x_ERROR, 1,
+ "timed out waiting for command result");
+ return -EIO;
+ }
+
+ if (sti7109->result_len > sti7109->result_max_len) {
+ sti7109->result_len = sti7109->result_max_len;
+ dprintk(SAA716x_NOTICE, 1,
+ "not enough space in result buffer");
+ }
+ }
+
+ return 0;
+}
+
+int sti7109_raw_cmd(struct sti7109_dev * sti7109, osd_raw_cmd_t * cmd)
+{
+ struct saa716x_dev * saa716x = sti7109->dev;
+ int err;
+
+ if (cmd->cmd_len > SIZE_CMD_DATA) {
+ dprintk(SAA716x_ERROR, 1, "command too long");
+ return -EFAULT;
+ }
+
+ mutex_lock(&sti7109->cmd_lock);
+
+ err = -EFAULT;
+ if (copy_from_user(sti7109->cmd_data, (void __user *)cmd->cmd_data,
+ cmd->cmd_len))
+ goto out;
+
+ sti7109->cmd_len = cmd->cmd_len;
+ sti7109->result_max_len = cmd->result_len;
+
+ err = sti7109_do_raw_cmd(sti7109);
+ if (err)
+ goto out;
+
+ cmd->result_len = sti7109->result_len;
+ if (sti7109->result_len > 0) {
+ if (copy_to_user((void __user *)cmd->result_data,
+ sti7109->result_data,
+ sti7109->result_len))
+ err = -EFAULT;
+ }
+
+out:
+ mutex_unlock(&sti7109->cmd_lock);
+ return err;
+}
+
+static int sti7109_do_raw_osd_cmd(struct sti7109_dev * sti7109)
+{
+ struct saa716x_dev * saa716x = sti7109->dev;
+ unsigned long timeout;
+
+ timeout = 1 * HZ;
+ timeout = wait_event_interruptible_timeout(sti7109->osd_cmd_ready_wq,
+ sti7109->osd_cmd_ready == 1,
+ timeout);
+
+ if (timeout == -ERESTARTSYS || sti7109->osd_cmd_ready == 0) {
+ if (timeout == -ERESTARTSYS) {
+ /* a signal arrived */
+ dprintk(SAA716x_ERROR, 1, "osd cmd ERESTARTSYS");
+ return -ERESTARTSYS;
+ }
+ dprintk(SAA716x_ERROR, 1,
+ "timed out waiting for osd command ready");
+ return -EIO;
+ }
+
+ sti7109->osd_cmd_ready = 0;
+ sti7109->osd_result_avail = 0;
+ saa716x_phi_write(saa716x, ADDR_OSD_CMD_DATA, sti7109->osd_cmd_data,
+ sti7109->osd_cmd_len);
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_PHI_ISET, ISR_OSD_CMD_MASK);
+
+ if (sti7109->osd_result_max_len > 0) {
+ timeout = 1 * HZ;
+ timeout = wait_event_interruptible_timeout(
+ sti7109->osd_result_avail_wq,
+ sti7109->osd_result_avail == 1,
+ timeout);
+
+ if (timeout == -ERESTARTSYS || sti7109->osd_result_avail == 0) {
+ sti7109->osd_result_len = 0;
+ if (timeout == -ERESTARTSYS) {
+ /* a signal arrived */
+ dprintk(SAA716x_ERROR, 1,
+ "osd result ERESTARTSYS");
+ return -ERESTARTSYS;
+ }
+ dprintk(SAA716x_ERROR, 1,
+ "timed out waiting for osd command result");
+ return -EIO;
+ }
+
+ if (sti7109->osd_result_len > sti7109->osd_result_max_len) {
+ sti7109->osd_result_len = sti7109->osd_result_max_len;
+ dprintk(SAA716x_NOTICE, 1,
+ "not enough space in result buffer");
+ }
+ }
+
+ return 0;
+}
+
+int sti7109_raw_osd_cmd(struct sti7109_dev * sti7109, osd_raw_cmd_t * cmd)
+{
+ struct saa716x_dev * saa716x = sti7109->dev;
+ int err;
+
+ if (cmd->cmd_len > SIZE_OSD_CMD_DATA) {
+ dprintk(SAA716x_ERROR, 1, "command too long");
+ return -EFAULT;
+ }
+
+ mutex_lock(&sti7109->osd_cmd_lock);
+
+ err = -EFAULT;
+ if (copy_from_user(sti7109->osd_cmd_data, (void __user *)cmd->cmd_data,
+ cmd->cmd_len))
+ goto out;
+
+ sti7109->osd_cmd_len = cmd->cmd_len;
+ sti7109->osd_result_max_len = cmd->result_len;
+
+ err = sti7109_do_raw_osd_cmd(sti7109);
+ if (err)
+ goto out;
+
+ cmd->result_len = sti7109->osd_result_len;
+ if (sti7109->osd_result_len > 0) {
+ if (copy_to_user((void __user *)cmd->result_data,
+ sti7109->osd_result_data,
+ sti7109->osd_result_len))
+ err = -EFAULT;
+ }
+
+out:
+ mutex_unlock(&sti7109->osd_cmd_lock);
+ return err;
+}
+
+static int sti7109_do_raw_data(struct sti7109_dev * sti7109, osd_raw_data_t * data)
+{
+ struct saa716x_dev * saa716x = sti7109->dev;
+ unsigned long timeout;
+ u16 blockSize;
+ u16 lastBlockSize;
+ u16 numBlocks;
+ u16 blockIndex;
+ u8 blockHeader[SIZE_BLOCK_HEADER];
+ u8 * blockPtr;
+ int activeBlock;
+
+ timeout = 1 * HZ;
+ timeout = wait_event_interruptible_timeout(sti7109->data_ready_wq,
+ sti7109->data_ready == 1,
+ timeout);
+
+ if (timeout == -ERESTARTSYS || sti7109->data_ready == 0) {
+ if (timeout == -ERESTARTSYS) {
+ /* a signal arrived */
+ dprintk(SAA716x_ERROR, 1, "data ERESTARTSYS");
+ return -ERESTARTSYS;
+ }
+ dprintk(SAA716x_ERROR, 1, "timed out waiting for data ready");
+ return -EIO;
+ }
+
+ sti7109->data_ready = 0;
+
+ /*
+ * 8 bytes is the size of the block header. Block header structure is:
+ * 16 bit - block index
+ * 16 bit - number of blocks
+ * 16 bit - current block data size
+ * 16 bit - block handle. This is used to reference the data in the
+ * command that uses it.
+ */
+ blockSize = (SIZE_BLOCK_DATA / 2) - SIZE_BLOCK_HEADER;
+ numBlocks = data->data_length / blockSize;
+ lastBlockSize = data->data_length % blockSize;
+ if (lastBlockSize > 0)
+ numBlocks++;
+
+ blockHeader[2] = (u8) (numBlocks >> 8);
+ blockHeader[3] = (u8) numBlocks;
+ blockHeader[6] = (u8) (sti7109->data_handle >> 8);
+ blockHeader[7] = (u8) sti7109->data_handle;
+ blockPtr = sti7109->data_buffer;
+ activeBlock = 0;
+ for (blockIndex = 0; blockIndex < numBlocks; blockIndex++) {
+ u32 addr;
+
+ if (lastBlockSize && (blockIndex == (numBlocks - 1)))
+ blockSize = lastBlockSize;
+
+ blockHeader[0] = (uint8_t) (blockIndex >> 8);
+ blockHeader[1] = (uint8_t) blockIndex;
+ blockHeader[4] = (uint8_t) (blockSize >> 8);
+ blockHeader[5] = (uint8_t) blockSize;
+
+ addr = ADDR_BLOCK_DATA + activeBlock * (SIZE_BLOCK_DATA / 2);
+ saa716x_phi_write(saa716x, addr, blockHeader,
+ SIZE_BLOCK_HEADER);
+ saa716x_phi_write(saa716x, addr + SIZE_BLOCK_HEADER, blockPtr,
+ blockSize);
+ activeBlock = (activeBlock + 1) & 1;
+ if (blockIndex > 0) {
+ timeout = 1 * HZ;
+ timeout = wait_event_timeout(sti7109->block_done_wq,
+ sti7109->block_done == 1,
+ timeout);
+
+ if (sti7109->block_done == 0) {
+ dprintk(SAA716x_ERROR, 1,
+ "timed out waiting for block done");
+ return -EIO;
+ }
+ }
+ sti7109->block_done = 0;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_PHI_ISET, ISR_BLOCK_MASK);
+ blockPtr += blockSize;
+ }
+ timeout = 1 * HZ;
+ timeout = wait_event_timeout(sti7109->block_done_wq,
+ sti7109->block_done == 1,
+ timeout);
+
+ if (sti7109->block_done == 0) {
+ dprintk(SAA716x_ERROR, 1, "timed out waiting for block done");
+ return -EIO;
+ }
+ sti7109->block_done = 0;
+
+ data->data_handle = sti7109->data_handle;
+ sti7109->data_handle++;
+ return 0;
+}
+
+int sti7109_raw_data(struct sti7109_dev * sti7109, osd_raw_data_t * data)
+{
+ struct saa716x_dev * saa716x = sti7109->dev;
+ int err;
+
+ if (data->data_length > MAX_DATA_LEN) {
+ dprintk(SAA716x_ERROR, 1, "data too big");
+ return -EFAULT;
+ }
+
+ mutex_lock(&sti7109->data_lock);
+
+ err = -EFAULT;
+ if (copy_from_user(sti7109->data_buffer,
+ (void __user *)data->data_buffer,
+ data->data_length))
+ goto out;
+
+ err = sti7109_do_raw_data(sti7109, data);
+ if (err)
+ goto out;
+
+out:
+ mutex_unlock(&sti7109->data_lock);
+ return err;
+}
+
+int sti7109_cmd_get_fw_version(struct sti7109_dev *sti7109, u32 *fw_version)
+{
+ int ret_val = -EINVAL;
+
+ mutex_lock(&sti7109->cmd_lock);
+
+ sti7109->cmd_data[0] = 0x00;
+ sti7109->cmd_data[1] = 0x04;
+ sti7109->cmd_data[2] = 0x00;
+ sti7109->cmd_data[3] = 0x00;
+ sti7109->cmd_data[4] = 0x00;
+ sti7109->cmd_data[5] = 0x00;
+ sti7109->cmd_len = 6;
+ sti7109->result_max_len = MAX_RESULT_LEN;
+
+ ret_val = sti7109_do_raw_cmd(sti7109);
+ if (ret_val == 0) {
+ *fw_version = (sti7109->result_data[6] << 16)
+ | (sti7109->result_data[7] << 8)
+ | sti7109->result_data[8];
+ }
+
+ mutex_unlock(&sti7109->cmd_lock);
+
+ return ret_val;
+}
+
+int sti7109_cmd_get_video_format(struct sti7109_dev *sti7109, video_size_t *vs)
+{
+ int ret_val = -EINVAL;
+
+ mutex_lock(&sti7109->cmd_lock);
+
+ sti7109->cmd_data[0] = 0x00;
+ sti7109->cmd_data[1] = 0x05; /* command length */
+ sti7109->cmd_data[2] = 0x00;
+ sti7109->cmd_data[3] = 0x01; /* A/V decoder command group */
+ sti7109->cmd_data[4] = 0x00;
+ sti7109->cmd_data[5] = 0x10; /* get video format info command */
+ sti7109->cmd_data[6] = 0x00; /* decoder index 0 */
+ sti7109->cmd_len = 7;
+ sti7109->result_max_len = MAX_RESULT_LEN;
+
+ ret_val = sti7109_do_raw_cmd(sti7109);
+ if (ret_val == 0) {
+ vs->w = (sti7109->result_data[7] << 8)
+ | sti7109->result_data[8];
+ vs->h = (sti7109->result_data[9] << 8)
+ | sti7109->result_data[10];
+ vs->aspect_ratio = sti7109->result_data[11] >> 4;
+ }
+
+ mutex_unlock(&sti7109->cmd_lock);
+
+ return ret_val;
+}
+
diff --git a/drivers/media/common/saa716x/saa716x_ff_cmd.h b/drivers/media/common/saa716x/saa716x_ff_cmd.h
new file mode 100644
index 0000000..fc79f08
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_ff_cmd.h
@@ -0,0 +1,16 @@
+#ifndef __SAA716x_FF_CMD_H
+#define __SAA716x_FF_CMD_H
+
+extern int sti7109_cmd_init(struct sti7109_dev *sti7109);
+extern int sti7109_raw_cmd(struct sti7109_dev * sti7109,
+ osd_raw_cmd_t * cmd);
+extern int sti7109_raw_osd_cmd(struct sti7109_dev * sti7109,
+ osd_raw_cmd_t * cmd);
+extern int sti7109_raw_data(struct sti7109_dev * sti7109,
+ osd_raw_data_t * data);
+extern int sti7109_cmd_get_fw_version(struct sti7109_dev *sti7109,
+ u32 *fw_version);
+extern int sti7109_cmd_get_video_format(struct sti7109_dev *sti7109,
+ video_size_t *vs);
+
+#endif /* __SAA716x_FF_CMD_H */
diff --git a/drivers/media/common/saa716x/saa716x_ff_ir.c b/drivers/media/common/saa716x/saa716x_ff_ir.c
new file mode 100644
index 0000000..3562478
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_ff_ir.c
@@ -0,0 +1,265 @@
+/*
+ * Driver for the remote control of the TT6400 DVB-S2 card
+ *
+ * Copyright (C) 2010 Oliver Endriss <o.endriss@gmx.de>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/input.h>
+
+#include "saa716x_spi.h"
+#include "saa716x_priv.h"
+#include "saa716x_ff.h"
+
+
+/* infrared remote control */
+struct infrared {
+ u16 key_map[128];
+ struct input_dev *input_dev;
+ char input_phys[32];
+ struct timer_list keyup_timer;
+ struct tasklet_struct tasklet;
+ u32 command;
+ u32 device_mask;
+ u8 protocol;
+ u16 last_key;
+ u16 last_toggle;
+ bool delay_timer_finished;
+};
+
+#define IR_RC5 0
+#define UP_TIMEOUT (HZ*7/25)
+
+
+/* key-up timer */
+static void ir_emit_keyup(unsigned long parm)
+{
+ struct infrared *ir = (struct infrared *) parm;
+
+ if (!ir || !test_bit(ir->last_key, ir->input_dev->key))
+ return;
+
+ input_report_key(ir->input_dev, ir->last_key, 0);
+ input_sync(ir->input_dev);
+}
+
+
+/* tasklet */
+static void ir_emit_key(unsigned long parm)
+{
+ struct saa716x_dev *saa716x = (struct saa716x_dev *) parm;
+ struct infrared *ir = saa716x->ir_priv;
+ u32 ircom = ir->command;
+ u8 data;
+ u8 addr;
+ u16 toggle;
+ u16 keycode;
+
+ /* extract device address and data */
+ if (ircom & 0x80000000) { /* CEC remote command */
+ addr = 0;
+ data = ircom & 0x7F;
+ toggle = 0;
+ } else {
+ switch (ir->protocol) {
+ case IR_RC5: /* extended RC5: 5 bits device address, 7 bits data */
+ addr = (ircom >> 6) & 0x1f;
+ /* data bits 1..6 */
+ data = ircom & 0x3f;
+ /* data bit 7 (inverted) */
+ if (!(ircom & 0x1000))
+ data |= 0x40;
+ toggle = ircom & 0x0800;
+ break;
+
+ default:
+ printk(KERN_ERR "%s: invalid protocol %x\n",
+ __func__, ir->protocol);
+ return;
+ }
+ }
+
+ input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data);
+ input_event(ir->input_dev, EV_MSC, MSC_SCAN, data);
+
+ keycode = ir->key_map[data];
+
+ dprintk(SAA716x_DEBUG, 0,
+ "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n",
+ __func__, ircom, addr, data, keycode);
+
+ /* check device address */
+ if (!(ir->device_mask & (1 << addr)))
+ return;
+
+ if (!keycode) {
+ printk(KERN_WARNING "%s: code %08x -> addr %i data 0x%02x -> unknown key!\n",
+ __func__, ircom, addr, data);
+ return;
+ }
+
+ if (timer_pending(&ir->keyup_timer)) {
+ del_timer(&ir->keyup_timer);
+ if (ir->last_key != keycode || toggle != ir->last_toggle) {
+ ir->delay_timer_finished = false;
+ input_event(ir->input_dev, EV_KEY, ir->last_key, 0);
+ input_event(ir->input_dev, EV_KEY, keycode, 1);
+ input_sync(ir->input_dev);
+ } else if (ir->delay_timer_finished) {
+ input_event(ir->input_dev, EV_KEY, keycode, 2);
+ input_sync(ir->input_dev);
+ }
+ } else {
+ ir->delay_timer_finished = false;
+ input_event(ir->input_dev, EV_KEY, keycode, 1);
+ input_sync(ir->input_dev);
+ }
+
+ ir->last_key = keycode;
+ ir->last_toggle = toggle;
+
+ ir->keyup_timer.expires = jiffies + UP_TIMEOUT;
+ add_timer(&ir->keyup_timer);
+
+}
+
+
+/* register with input layer */
+static void ir_register_keys(struct infrared *ir)
+{
+ int i;
+
+ set_bit(EV_KEY, ir->input_dev->evbit);
+ set_bit(EV_REP, ir->input_dev->evbit);
+ set_bit(EV_MSC, ir->input_dev->evbit);
+
+ set_bit(MSC_RAW, ir->input_dev->mscbit);
+ set_bit(MSC_SCAN, ir->input_dev->mscbit);
+
+ memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit));
+
+ for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) {
+ if (ir->key_map[i] > KEY_MAX)
+ ir->key_map[i] = 0;
+ else if (ir->key_map[i] > KEY_RESERVED)
+ set_bit(ir->key_map[i], ir->input_dev->keybit);
+ }
+
+ ir->input_dev->keycode = ir->key_map;
+ ir->input_dev->keycodesize = sizeof(ir->key_map[0]);
+ ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
+}
+
+
+/* called by the input driver after rep[REP_DELAY] ms */
+static void ir_repeat_key(unsigned long parm)
+{
+ struct infrared *ir = (struct infrared *) parm;
+
+ ir->delay_timer_finished = true;
+}
+
+
+/* interrupt handler */
+void saa716x_ir_handler(struct saa716x_dev *saa716x, u32 ir_cmd)
+{
+ struct infrared *ir = saa716x->ir_priv;
+
+ if (!ir)
+ return;
+
+ ir->command = ir_cmd;
+ tasklet_schedule(&ir->tasklet);
+}
+
+
+int saa716x_ir_init(struct saa716x_dev *saa716x)
+{
+ struct input_dev *input_dev;
+ struct infrared *ir;
+ int rc;
+ int i;
+
+ if (!saa716x)
+ return -ENOMEM;
+
+ ir = kzalloc(sizeof(struct infrared), GFP_KERNEL);
+ if (!ir)
+ return -ENOMEM;
+
+ init_timer(&ir->keyup_timer);
+ ir->keyup_timer.function = ir_emit_keyup;
+ ir->keyup_timer.data = (unsigned long) ir;
+
+ input_dev = input_allocate_device();
+ if (!input_dev)
+ goto err;
+
+ ir->input_dev = input_dev;
+ input_dev->name = "TT6400 DVB IR receiver";
+ snprintf(ir->input_phys, sizeof(ir->input_phys),
+ "pci-%s/ir0", pci_name(saa716x->pdev));
+ input_dev->phys = ir->input_phys;
+ input_dev->id.bustype = BUS_PCI;
+ input_dev->id.version = 1;
+ input_dev->id.vendor = saa716x->pdev->subsystem_vendor;
+ input_dev->id.product = saa716x->pdev->subsystem_device;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+ input_dev->dev.parent = &saa716x->pdev->dev;
+#else
+ input_dev->cdev.dev = &saa716x->pdev->dev;
+#endif
+ rc = input_register_device(input_dev);
+ if (rc)
+ goto err;
+
+ /* TODO: fix setup/keymap */
+ ir->protocol = IR_RC5;
+ ir->device_mask = 0xffffffff;
+ for (i = 0; i < ARRAY_SIZE(ir->key_map); i++)
+ ir->key_map[i] = i+1;
+ ir_register_keys(ir);
+
+ /* override repeat timer */
+ input_dev->timer.function = ir_repeat_key;
+ input_dev->timer.data = (unsigned long) ir;
+
+ tasklet_init(&ir->tasklet, ir_emit_key, (unsigned long) saa716x);
+ saa716x->ir_priv = ir;
+
+ return 0;
+
+err:
+ if (ir->input_dev)
+ input_free_device(ir->input_dev);
+ kfree(ir);
+ return -ENOMEM;
+}
+
+
+void saa716x_ir_exit(struct saa716x_dev *saa716x)
+{
+ struct infrared *ir = saa716x->ir_priv;
+
+ saa716x->ir_priv = NULL;
+ tasklet_kill(&ir->tasklet);
+ del_timer_sync(&ir->keyup_timer);
+ input_unregister_device(ir->input_dev);
+ kfree(ir);
+}
diff --git a/drivers/media/common/saa716x/saa716x_ff_main.c b/drivers/media/common/saa716x/saa716x_ff_main.c
new file mode 100644
index 0000000..34093c2
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_ff_main.c
@@ -0,0 +1,1535 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/byteorder.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include <linux/i2c.h>
+
+#include <linux/dvb/video.h>
+#include <linux/dvb/audio.h>
+#include <linux/dvb/osd.h>
+
+#include "saa716x_mod.h"
+
+#include "saa716x_dma_reg.h"
+#include "saa716x_fgpi_reg.h"
+#include "saa716x_greg_reg.h"
+#include "saa716x_phi_reg.h"
+#include "saa716x_spi_reg.h"
+#include "saa716x_msi_reg.h"
+
+#include "saa716x_vip.h"
+#include "saa716x_aip.h"
+#include "saa716x_msi.h"
+#include "saa716x_adap.h"
+#include "saa716x_gpio.h"
+#include "saa716x_phi.h"
+#include "saa716x_rom.h"
+#include "saa716x_spi.h"
+#include "saa716x_priv.h"
+
+#include "saa716x_ff.h"
+#include "saa716x_ff_cmd.h"
+
+#include "stv6110x.h"
+#include "stv090x.h"
+#include "isl6423.h"
+
+unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+
+unsigned int int_type;
+module_param(int_type, int, 0644);
+MODULE_PARM_DESC(int_type, "force Interrupt Handler type: 0=INT-A, 1=MSI, 2=MSI-X. default INT-A mode");
+
+unsigned int int_count_enable;
+module_param(int_count_enable, int, 0644);
+MODULE_PARM_DESC(int_count_enable, "enable counting of interrupts");
+
+#define DRIVER_NAME "SAA716x FF"
+
+static int saa716x_ff_fpga_init(struct saa716x_dev *saa716x)
+{
+ struct sti7109_dev *sti7109 = saa716x->priv;
+ int fpgaInit;
+ int fpgaDone;
+ int rounds;
+ int ret;
+ const struct firmware *fw;
+
+ /* request the FPGA firmware, this will block until someone uploads it */
+ ret = request_firmware(&fw, "dvb-ttpremium-fpga-01.fw", &saa716x->pdev->dev);
+ if (ret) {
+ if (ret == -ENOENT) {
+ printk(KERN_ERR "dvb-ttpremium: could not load FPGA firmware,"
+ " file not found: dvb-ttpremium-fpga-01.fw\n");
+ printk(KERN_ERR "dvb-ttpremium: usually this should be in "
+ "/usr/lib/hotplug/firmware or /lib/firmware\n");
+ } else
+ printk(KERN_ERR "dvb-ttpremium: cannot request firmware"
+ " (error %i)\n", ret);
+ return -EINVAL;
+ }
+
+ /* set FPGA PROGRAMN high */
+ saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_FPGA_PROGRAMN, 1);
+ msleep(10);
+
+ /* set FPGA PROGRAMN low to set it into configuration mode */
+ saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_FPGA_PROGRAMN, 0);
+ msleep(10);
+
+ /* set FPGA PROGRAMN high to start configuration process */
+ saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_FPGA_PROGRAMN, 1);
+
+ rounds = 0;
+ fpgaInit = saa716x_gpio_read(saa716x, TT_PREMIUM_GPIO_FPGA_INITN);
+ while (fpgaInit == 0 && rounds < 5000) {
+ //msleep(1);
+ fpgaInit = saa716x_gpio_read(saa716x, TT_PREMIUM_GPIO_FPGA_INITN);
+ rounds++;
+ }
+ dprintk(SAA716x_INFO, 1, "SAA716x FF FPGA INITN=%d, rounds=%d",
+ fpgaInit, rounds);
+
+ SAA716x_EPWR(SPI, SPI_CLOCK_COUNTER, 0x08);
+ SAA716x_EPWR(SPI, SPI_CONTROL_REG, SPI_MODE_SELECT);
+
+ msleep(10);
+
+ fpgaDone = saa716x_gpio_read(saa716x, TT_PREMIUM_GPIO_FPGA_DONE);
+ dprintk(SAA716x_INFO, 1, "SAA716x FF FPGA DONE=%d", fpgaDone);
+ dprintk(SAA716x_INFO, 1, "SAA716x FF FPGA write bitstream");
+ saa716x_spi_write(saa716x, fw->data, fw->size);
+ dprintk(SAA716x_INFO, 1, "SAA716x FF FPGA write bitstream done");
+ fpgaDone = saa716x_gpio_read(saa716x, TT_PREMIUM_GPIO_FPGA_DONE);
+ dprintk(SAA716x_INFO, 1, "SAA716x FF FPGA DONE=%d", fpgaDone);
+
+ msleep(10);
+
+ release_firmware(fw);
+
+ if (!fpgaDone) {
+ printk(KERN_ERR "SAA716x FF FPGA is not responding, did you "
+ "connect the power supply?\n");
+ return -EINVAL;
+ }
+
+ sti7109->fpga_version = SAA716x_EPRD(PHI_1, FPGA_ADDR_VERSION);
+ printk(KERN_INFO "SAA716x FF FPGA version %X.%02X\n",
+ sti7109->fpga_version >> 8, sti7109->fpga_version & 0xFF);
+
+ return 0;
+}
+
+static int saa716x_ff_st7109_init(struct saa716x_dev *saa716x)
+{
+ int i;
+ int length;
+ u32 requestedBlock;
+ u32 writtenBlock;
+ u32 numBlocks;
+ u32 blockSize;
+ u32 lastBlockSize;
+ u64 startTime;
+ u64 currentTime;
+ u64 waitTime;
+ int ret;
+ const struct firmware *fw;
+ u32 loaderVersion;
+
+ /* request the st7109 loader, this will block until someone uploads it */
+ ret = request_firmware(&fw, "dvb-ttpremium-loader-01.fw", &saa716x->pdev->dev);
+ if (ret) {
+ if (ret == -ENOENT) {
+ printk(KERN_ERR "dvb-ttpremium: could not load ST7109 loader,"
+ " file not found: dvb-ttpremium-loader-01.fw\n");
+ printk(KERN_ERR "dvb-ttpremium: usually this should be in "
+ "/usr/lib/hotplug/firmware or /lib/firmware\n");
+ } else
+ printk(KERN_ERR "dvb-ttpremium: cannot request firmware"
+ " (error %i)\n", ret);
+ return -EINVAL;
+ }
+ loaderVersion = (fw->data[0x1385] << 8) | fw->data[0x1384];
+ printk(KERN_INFO "SAA716x FF loader version %X.%02X\n",
+ loaderVersion >> 8, loaderVersion & 0xFF);
+
+ saa716x_phi_write(saa716x, 0, fw->data, fw->size);
+ msleep(10);
+
+ release_firmware(fw);
+
+ /* take ST out of reset */
+ saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_RESET_BACKEND, 1);
+
+ startTime = jiffies;
+ waitTime = 0;
+ do {
+ requestedBlock = SAA716x_EPRD(PHI_1, 0x3ffc);
+ if (requestedBlock == 1)
+ break;
+
+ currentTime = jiffies;
+ waitTime = currentTime - startTime;
+ } while (waitTime < (1 * HZ));
+
+ if (waitTime >= 1 * HZ) {
+ dprintk(SAA716x_ERROR, 1, "STi7109 seems to be DEAD!");
+ return -1;
+ }
+ dprintk(SAA716x_INFO, 1, "STi7109 ready after %llu ticks", waitTime);
+
+ /* request the st7109 firmware, this will block until someone uploads it */
+ ret = request_firmware(&fw, "dvb-ttpremium-st7109-01.fw", &saa716x->pdev->dev);
+ if (ret) {
+ if (ret == -ENOENT) {
+ printk(KERN_ERR "dvb-ttpremium: could not load ST7109 firmware,"
+ " file not found: dvb-ttpremium-st7109-01.fw\n");
+ printk(KERN_ERR "dvb-ttpremium: usually this should be in "
+ "/usr/lib/hotplug/firmware or /lib/firmware\n");
+ } else
+ printk(KERN_ERR "dvb-ttpremium: cannot request firmware"
+ " (error %i)\n", ret);
+ return -EINVAL;
+ }
+
+ dprintk(SAA716x_INFO, 1, "SAA716x FF download ST7109 firmware");
+ writtenBlock = 0;
+ blockSize = 0x3c00;
+ length = fw->size;
+ numBlocks = length / blockSize;
+ lastBlockSize = length % blockSize;
+ for (i = 0; i < length; i += blockSize) {
+ writtenBlock++;
+ /* write one block (last may differ from blockSize) */
+ if (lastBlockSize && writtenBlock == (numBlocks + 1))
+ saa716x_phi_write(saa716x, 0, &fw->data[i], lastBlockSize);
+ else
+ saa716x_phi_write(saa716x, 0, &fw->data[i], blockSize);
+
+ SAA716x_EPWR(PHI_1, 0x3ff8, writtenBlock);
+ startTime = jiffies;
+ waitTime = 0;
+ do {
+ requestedBlock = SAA716x_EPRD(PHI_1, 0x3ffc);
+ if (requestedBlock == (writtenBlock + 1))
+ break;
+
+ currentTime = jiffies;
+ waitTime = currentTime - startTime;
+ } while (waitTime < (1 * HZ));
+
+ if (waitTime >= 1 * HZ) {
+ dprintk(SAA716x_ERROR, 1, "STi7109 seems to be DEAD!");
+ release_firmware(fw);
+ return -1;
+ }
+ }
+
+ /* disable frontend support through ST firmware */
+ SAA716x_EPWR(PHI_1, 0x3ff4, 1);
+
+ /* indicate end of transfer */
+ writtenBlock++;
+ writtenBlock |= 0x80000000;
+ SAA716x_EPWR(PHI_1, 0x3ff8, writtenBlock);
+
+ dprintk(SAA716x_INFO, 1, "SAA716x FF download ST7109 firmware done");
+
+ release_firmware(fw);
+
+ return 0;
+}
+
+static int saa716x_usercopy(struct dvb_device *dvbdev,
+ unsigned int cmd, unsigned long arg,
+ int (*func)(struct dvb_device *dvbdev,
+ unsigned int cmd, void *arg))
+{
+ char sbuf[128];
+ void *mbuf = NULL;
+ void *parg = NULL;
+ int err = -EINVAL;
+
+ /* Copy arguments into temp kernel buffer */
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_NONE:
+ /*
+ * For this command, the pointer is actually an integer
+ * argument.
+ */
+ parg = (void *) arg;
+ break;
+ case _IOC_READ: /* some v4l ioctls are marked wrong ... */
+ case _IOC_WRITE:
+ case (_IOC_WRITE | _IOC_READ):
+ if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+ parg = sbuf;
+ } else {
+ /* too big to allocate from stack */
+ mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
+ if (NULL == mbuf)
+ return -ENOMEM;
+ parg = mbuf;
+ }
+
+ err = -EFAULT;
+ if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+ goto out;
+ break;
+ }
+
+ /* call driver */
+ if ((err = func(dvbdev, cmd, parg)) == -ENOIOCTLCMD)
+ err = -EINVAL;
+
+ if (err < 0)
+ goto out;
+
+ /* Copy results into user buffer */
+ switch (_IOC_DIR(cmd))
+ {
+ case _IOC_READ:
+ case (_IOC_WRITE | _IOC_READ):
+ if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+ err = -EFAULT;
+ break;
+ }
+
+out:
+ kfree(mbuf);
+ return err;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) && !defined(EXPERIMENTAL_TREE)
+static int dvb_osd_ioctl(struct inode *inode, struct file *file,
+#else
+static long dvb_osd_ioctl(struct file *file,
+#endif
+ unsigned int cmd, unsigned long arg)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct sti7109_dev *sti7109 = dvbdev->priv;
+ int err = -EINVAL;
+
+ if (!dvbdev)
+ return -ENODEV;
+
+ if (cmd == OSD_RAW_CMD) {
+ osd_raw_cmd_t raw_cmd;
+ u8 hdr[4];
+
+ err = -EFAULT;
+ if (copy_from_user(&raw_cmd, (void __user *)arg,
+ _IOC_SIZE(cmd)))
+ goto out;
+
+ if (copy_from_user(hdr, (void __user *)raw_cmd.cmd_data, 4))
+ goto out;
+
+ if (hdr[3] == 4)
+ err = sti7109_raw_osd_cmd(sti7109, &raw_cmd);
+ else
+ err = sti7109_raw_cmd(sti7109, &raw_cmd);
+
+ if (err)
+ goto out;
+
+ if (copy_to_user((void __user *)arg, &raw_cmd, _IOC_SIZE(cmd)))
+ err = -EFAULT;
+ }
+ else if (cmd == OSD_RAW_DATA) {
+ osd_raw_data_t raw_data;
+
+ err = -EFAULT;
+ if (copy_from_user(&raw_data, (void __user *)arg,
+ _IOC_SIZE(cmd)))
+ goto out;
+
+ err = sti7109_raw_data(sti7109, &raw_data);
+ if (err)
+ goto out;
+
+ if (copy_to_user((void __user *)arg, &raw_data, _IOC_SIZE(cmd)))
+ err = -EFAULT;
+ }
+
+out:
+ return err;
+}
+
+static struct file_operations dvb_osd_fops = {
+ .owner = THIS_MODULE,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) && !defined(EXPERIMENTAL_TREE)
+ .ioctl = dvb_osd_ioctl,
+#else
+ .unlocked_ioctl = dvb_osd_ioctl,
+#endif
+ .open = dvb_generic_open,
+ .release = dvb_generic_release,
+};
+
+static struct dvb_device dvbdev_osd = {
+ .priv = NULL,
+ .users = 2,
+ .writers = 2,
+ .fops = &dvb_osd_fops,
+ .kernel_ioctl = NULL,
+};
+
+static int saa716x_ff_osd_exit(struct saa716x_dev *saa716x)
+{
+ struct sti7109_dev *sti7109 = saa716x->priv;
+
+ dvb_unregister_device(sti7109->osd_dev);
+ return 0;
+}
+
+static int saa716x_ff_osd_init(struct saa716x_dev *saa716x)
+{
+ struct saa716x_adapter *saa716x_adap = saa716x->saa716x_adap;
+ struct sti7109_dev *sti7109 = saa716x->priv;
+
+ dvb_register_device(&saa716x_adap->dvb_adapter,
+ &sti7109->osd_dev,
+ &dvbdev_osd,
+ sti7109,
+ DVB_DEVICE_OSD);
+
+ return 0;
+}
+
+static int do_dvb_audio_ioctl(struct dvb_device *dvbdev,
+ unsigned int cmd, void *parg)
+{
+ struct sti7109_dev *sti7109 = dvbdev->priv;
+ //struct saa716x_dev *saa716x = sti7109->dev;
+ int ret = 0;
+
+ switch (cmd) {
+ case AUDIO_GET_PTS:
+ {
+ *(u64 *)parg = sti7109->audio_pts;
+ break;
+ }
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+ return ret;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) && !defined(EXPERIMENTAL_TREE)
+static int dvb_audio_ioctl(struct inode *inode, struct file *file,
+#else
+static long dvb_audio_ioctl(struct file *file,
+#endif
+ unsigned int cmd, unsigned long arg)
+{
+ struct dvb_device *dvbdev = file->private_data;
+
+ if (!dvbdev)
+ return -ENODEV;
+
+ return saa716x_usercopy (dvbdev, cmd, arg, do_dvb_audio_ioctl);
+}
+
+static struct file_operations dvb_audio_fops = {
+ .owner = THIS_MODULE,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) && !defined(EXPERIMENTAL_TREE)
+ .ioctl = dvb_audio_ioctl,
+#else
+ .unlocked_ioctl = dvb_audio_ioctl,
+#endif
+ .open = dvb_generic_open,
+ .release = dvb_generic_release,
+};
+
+static struct dvb_device dvbdev_audio = {
+ .priv = NULL,
+ .users = 1,
+ .writers = 1,
+ .fops = &dvb_audio_fops,
+ .kernel_ioctl = NULL,
+};
+
+static int saa716x_ff_audio_exit(struct saa716x_dev *saa716x)
+{
+ struct sti7109_dev *sti7109 = saa716x->priv;
+
+ dvb_unregister_device(sti7109->audio_dev);
+ return 0;
+}
+
+static int saa716x_ff_audio_init(struct saa716x_dev *saa716x)
+{
+ struct saa716x_adapter *saa716x_adap = saa716x->saa716x_adap;
+ struct sti7109_dev *sti7109 = saa716x->priv;
+
+ dvb_register_device(&saa716x_adap->dvb_adapter,
+ &sti7109->audio_dev,
+ &dvbdev_audio,
+ sti7109,
+ DVB_DEVICE_AUDIO);
+
+ return 0;
+}
+
+static void fifo_worker(unsigned long data)
+{
+ struct saa716x_dev *saa716x = (struct saa716x_dev *) data;
+ struct sti7109_dev *sti7109 = saa716x->priv;
+ u32 fifoCtrl;
+ u32 fifoStat;
+ u16 fifoSize;
+ u16 fifoUsage;
+ u16 fifoFree;
+ int len;
+
+ fifoCtrl = SAA716x_EPRD(PHI_1, FPGA_ADDR_FIFO_CTRL);
+ fifoStat = SAA716x_EPRD(PHI_1, FPGA_ADDR_FIFO_STAT);
+ fifoSize = (u16) (fifoStat >> 16);
+ fifoUsage = (u16) fifoStat;
+ fifoFree = fifoSize - fifoUsage;
+ spin_lock(&sti7109->tsout.lock);
+ len = dvb_ringbuffer_avail(&sti7109->tsout);
+ if (len > fifoFree)
+ len = fifoFree;
+ if (len >= TS_SIZE)
+ {
+ while (len >= TS_SIZE)
+ {
+ dvb_ringbuffer_read(&sti7109->tsout, sti7109->tsbuf, (size_t) TS_SIZE);
+ saa716x_phi_write_fifo(saa716x, sti7109->tsbuf, TS_SIZE);
+ len -= TS_SIZE;
+ }
+ wake_up(&sti7109->tsout.queue);
+ fifoCtrl |= 0x4;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_FIFO_CTRL, fifoCtrl);
+ }
+ spin_unlock(&sti7109->tsout.lock);
+}
+
+#define FREE_COND_TS (dvb_ringbuffer_free(&sti7109->tsout) >= TS_SIZE)
+
+static ssize_t dvb_video_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct sti7109_dev *sti7109 = dvbdev->priv;
+ struct saa716x_dev *saa716x = sti7109->dev;
+ unsigned long todo = count;
+
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+ return -EPERM;
+/*
+ if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY)
+ return -EPERM;
+*/
+ if ((file->f_flags & O_NONBLOCK) && !FREE_COND_TS)
+ return -EWOULDBLOCK;
+
+ while (todo >= TS_SIZE) {
+ if (!FREE_COND_TS) {
+ if (file->f_flags & O_NONBLOCK)
+ break;
+ if (wait_event_interruptible(sti7109->tsout.queue, FREE_COND_TS))
+ break;
+ }
+ dvb_ringbuffer_write(&sti7109->tsout, buf, TS_SIZE);
+ todo -= TS_SIZE;
+ buf += TS_SIZE;
+ }
+
+ if (count > todo) {
+ u32 fifoCtrl;
+
+ fifoCtrl = SAA716x_EPRD(PHI_1, FPGA_ADDR_FIFO_CTRL);
+ fifoCtrl |= 0x4;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_FIFO_CTRL, fifoCtrl);
+ }
+
+ return count - todo;
+}
+
+static unsigned int dvb_video_poll(struct file *file, poll_table *wait)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct sti7109_dev *sti7109 = dvbdev->priv;
+ unsigned int mask = 0;
+
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY)
+ poll_wait(file, &sti7109->tsout.queue, wait);
+
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+ if (1/*sti7109->playing*/) {
+ if (FREE_COND_TS)
+ mask |= (POLLOUT | POLLWRNORM);
+ } else /* if not playing: may play if asked for */
+ mask |= (POLLOUT | POLLWRNORM);
+ }
+
+ return mask;
+}
+
+static int do_dvb_video_ioctl(struct dvb_device *dvbdev,
+ unsigned int cmd, void *parg)
+{
+ struct sti7109_dev *sti7109 = dvbdev->priv;
+ struct saa716x_dev *saa716x = sti7109->dev;
+ int ret = 0;
+
+ switch (cmd) {
+ case VIDEO_SELECT_SOURCE:
+ {
+ video_stream_source_t stream_source;
+
+ stream_source = (video_stream_source_t) parg;
+ if (stream_source == VIDEO_SOURCE_DEMUX) {
+ /* stop and reset FIFO 1 */
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_FIFO_CTRL, 1);
+ }
+ else {
+ dvb_ringbuffer_flush_spinlock_wakeup(&sti7109->tsout);
+ /* reset FIFO 1 */
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_FIFO_CTRL, 1);
+ /* start FIFO 1 */
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_FIFO_CTRL, 2);
+ }
+ break;
+ }
+ case VIDEO_CLEAR_BUFFER:
+ {
+ dvb_ringbuffer_flush_spinlock_wakeup(&sti7109->tsout);
+ break;
+ }
+ case VIDEO_GET_PTS:
+ {
+ *(u64 *)parg = sti7109->video_pts;
+ break;
+ }
+ case VIDEO_GET_SIZE:
+ {
+ ret = sti7109_cmd_get_video_format(sti7109, (video_size_t *) parg);
+ break;
+ }
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+ return ret;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) && !defined(EXPERIMENTAL_TREE)
+static int dvb_video_ioctl(struct inode *inode, struct file *file,
+#else
+static long dvb_video_ioctl(struct file *file,
+#endif
+ unsigned int cmd, unsigned long arg)
+{
+ struct dvb_device *dvbdev = file->private_data;
+
+ if (!dvbdev)
+ return -ENODEV;
+
+ return saa716x_usercopy (dvbdev, cmd, arg, do_dvb_video_ioctl);
+}
+
+static struct file_operations dvb_video_fops = {
+ .owner = THIS_MODULE,
+ .write = dvb_video_write,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) && !defined(EXPERIMENTAL_TREE)
+ .ioctl = dvb_video_ioctl,
+#else
+ .unlocked_ioctl = dvb_video_ioctl,
+#endif
+ .open = dvb_generic_open,
+ .release = dvb_generic_release,
+ .poll = dvb_video_poll,
+};
+
+static struct dvb_device dvbdev_video = {
+ .priv = NULL,
+ .users = 1,
+ .writers = 1,
+ .fops = &dvb_video_fops,
+ .kernel_ioctl = NULL,
+};
+
+static int saa716x_ff_video_exit(struct saa716x_dev *saa716x)
+{
+ struct sti7109_dev *sti7109 = saa716x->priv;
+
+ tasklet_kill(&sti7109->fifo_tasklet);
+ dvb_unregister_device(sti7109->video_dev);
+ return 0;
+}
+
+static int saa716x_ff_video_init(struct saa716x_dev *saa716x)
+{
+ struct saa716x_adapter *saa716x_adap = saa716x->saa716x_adap;
+ struct sti7109_dev *sti7109 = saa716x->priv;
+
+ dvb_ringbuffer_init(&sti7109->tsout, sti7109->iobuf, TSOUT_LEN);
+ sti7109->tsbuf = (u8 *) (sti7109->iobuf + TSOUT_LEN);
+
+ dvb_register_device(&saa716x_adap->dvb_adapter,
+ &sti7109->video_dev,
+ &dvbdev_video,
+ sti7109,
+ DVB_DEVICE_VIDEO);
+
+ tasklet_init(&sti7109->fifo_tasklet, fifo_worker,
+ (unsigned long)saa716x);
+
+ return 0;
+}
+
+static int saa716x_ff_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+ struct saa716x_dev *saa716x;
+ struct sti7109_dev *sti7109;
+ int err = 0;
+ u32 value;
+ unsigned long timeout;
+ u32 fw_version;
+
+ saa716x = kzalloc(sizeof (struct saa716x_dev), GFP_KERNEL);
+ if (saa716x == NULL) {
+ printk(KERN_ERR "saa716x_budget_pci_probe ERROR: out of memory\n");
+ err = -ENOMEM;
+ goto fail0;
+ }
+
+ saa716x->verbose = verbose;
+ saa716x->int_type = int_type;
+ saa716x->pdev = pdev;
+ saa716x->config = (struct saa716x_config *) pci_id->driver_data;
+
+ err = saa716x_pci_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x PCI Initialization failed");
+ goto fail1;
+ }
+
+ err = saa716x_cgu_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x CGU Init failed");
+ goto fail1;
+ }
+
+ err = saa716x_core_boot(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x Core Boot failed");
+ goto fail2;
+ }
+ dprintk(SAA716x_DEBUG, 1, "SAA716x Core Boot Success");
+
+ err = saa716x_msi_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x MSI Init failed");
+ goto fail2;
+ }
+
+ err = saa716x_jetpack_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x Jetpack core initialization failed");
+ goto fail1;
+ }
+
+ err = saa716x_i2c_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x I2C Initialization failed");
+ goto fail3;
+ }
+
+ err = saa716x_phi_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x PHI Initialization failed");
+ goto fail3;
+ }
+
+ saa716x_gpio_init(saa716x);
+
+ /* prepare the sti7109 device struct */
+ sti7109 = kzalloc(sizeof(struct sti7109_dev), GFP_KERNEL);
+ if (!sti7109) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x: out of memory");
+ goto fail3;
+ }
+
+ sti7109->dev = saa716x;
+
+ sti7109->iobuf = vmalloc(TSOUT_LEN + TSBUF_LEN + MAX_DATA_LEN);
+ if (!sti7109->iobuf)
+ goto fail4;
+
+ sti7109_cmd_init(sti7109);
+
+ sti7109->int_count_enable = int_count_enable;
+ sti7109->total_int_count = 0;
+ memset(sti7109->fgpi_int_count, 0, sizeof(sti7109->fgpi_int_count));
+ memset(sti7109->i2c_int_count, 0, sizeof(sti7109->i2c_int_count));
+ sti7109->ext_int_total_count = 0;
+ memset(sti7109->ext_int_source_count, 0, sizeof(sti7109->ext_int_source_count));
+ sti7109->last_int_ticks = jiffies;
+
+ saa716x->priv = sti7109;
+
+ saa716x_gpio_set_output(saa716x, TT_PREMIUM_GPIO_POWER_ENABLE);
+ saa716x_gpio_set_output(saa716x, TT_PREMIUM_GPIO_RESET_BACKEND);
+ saa716x_gpio_set_output(saa716x, TT_PREMIUM_GPIO_FPGA_CS0);
+ saa716x_gpio_set_mode(saa716x, TT_PREMIUM_GPIO_FPGA_CS0, 1);
+ saa716x_gpio_set_output(saa716x, TT_PREMIUM_GPIO_FPGA_CS1);
+ saa716x_gpio_set_mode(saa716x, TT_PREMIUM_GPIO_FPGA_CS1, 1);
+ saa716x_gpio_set_output(saa716x, TT_PREMIUM_GPIO_FPGA_PROGRAMN);
+ saa716x_gpio_set_input(saa716x, TT_PREMIUM_GPIO_FPGA_DONE);
+ saa716x_gpio_set_input(saa716x, TT_PREMIUM_GPIO_FPGA_INITN);
+
+ /* hold ST in reset */
+ saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_RESET_BACKEND, 0);
+
+ /* enable board power */
+ saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_POWER_ENABLE, 1);
+ msleep(100);
+
+ err = saa716x_ff_fpga_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x FF FPGA Initialization failed");
+ goto fail5;
+ }
+
+ /* configure TS muxer */
+ if (sti7109->fpga_version < 0x110) {
+ /* select FIFO 1 for TS mux 3 */
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_TSR_MUX3, 4);
+ } else {
+ /* select FIFO 1 for TS mux 3 */
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_TSR_MUX3, 1);
+ }
+
+ /* enable interrupts from ST7109 -> PC */
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICTRL, 0x3);
+
+ value = SAA716x_EPRD(MSI, MSI_CONFIG33);
+ value &= 0xFCFFFFFF;
+ value |= MSI_INT_POL_EDGE_FALL;
+ SAA716x_EPWR(MSI, MSI_CONFIG33, value);
+ SAA716x_EPWR(MSI, MSI_INT_ENA_SET_H, MSI_INT_EXTINT_0);
+
+ /* enable tuner reset */
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_PIO_CTRL, 0);
+ msleep(50);
+ /* disable tuner reset */
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_PIO_CTRL, 1);
+
+ err = saa716x_ff_st7109_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x FF STi7109 initialization failed");
+ goto fail5;
+ }
+
+ err = saa716x_dump_eeprom(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x EEPROM dump failed");
+ }
+
+ err = saa716x_eeprom_data(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x EEPROM dump failed");
+ }
+
+ /* enable FGPI2 and FGPI3 for TS inputs */
+ SAA716x_EPWR(GREG, GREG_VI_CTRL, 0x0689F04);
+ SAA716x_EPWR(GREG, GREG_FGPI_CTRL, 0x280);
+
+ err = saa716x_dvb_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x DVB initialization failed");
+ goto fail6;
+ }
+
+ /* wait a maximum of 10 seconds for the STi7109 to boot */
+ timeout = 10 * HZ;
+ timeout = wait_event_interruptible_timeout(sti7109->boot_finish_wq,
+ sti7109->boot_finished == 1,
+ timeout);
+
+ if (timeout == -ERESTARTSYS || sti7109->boot_finished == 0) {
+ if (timeout == -ERESTARTSYS) {
+ /* a signal arrived */
+ goto fail6;
+ }
+ dprintk(SAA716x_ERROR, 1, "timed out waiting for boot finish");
+ err = -1;
+ goto fail6;
+ }
+ dprintk(SAA716x_INFO, 1, "STi7109 finished booting");
+
+ err = saa716x_ff_video_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x FF VIDEO initialization failed");
+ goto fail7;
+ }
+
+ err = saa716x_ff_audio_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x FF AUDIO initialization failed");
+ goto fail8;
+ }
+
+ err = saa716x_ff_osd_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x FF OSD initialization failed");
+ goto fail9;
+ }
+
+ err = sti7109_cmd_get_fw_version(sti7109, &fw_version);
+ if (!err) {
+ printk(KERN_INFO "SAA716x FF firmware version %X.%X.%X\n",
+ (fw_version >> 16) & 0xFF, (fw_version >> 8) & 0xFF,
+ fw_version & 0xFF);
+ }
+
+ err = saa716x_ir_init(saa716x);
+ if (err)
+ goto fail9;
+
+ return 0;
+
+fail9:
+ saa716x_ff_osd_exit(saa716x);
+fail8:
+ saa716x_ff_audio_exit(saa716x);
+fail7:
+ saa716x_ff_video_exit(saa716x);
+fail6:
+ saa716x_dvb_exit(saa716x);
+fail5:
+ SAA716x_EPWR(MSI, MSI_INT_ENA_CLR_H, MSI_INT_EXTINT_0);
+
+ /* disable board power */
+ saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_POWER_ENABLE, 0);
+
+ vfree(sti7109->iobuf);
+fail4:
+ kfree(sti7109);
+fail3:
+ saa716x_i2c_exit(saa716x);
+fail2:
+ saa716x_pci_exit(saa716x);
+fail1:
+ kfree(saa716x);
+fail0:
+ return err;
+}
+
+static void saa716x_ff_pci_remove(struct pci_dev *pdev)
+{
+ struct saa716x_dev *saa716x = pci_get_drvdata(pdev);
+ struct sti7109_dev *sti7109 = saa716x->priv;
+
+ saa716x_ir_exit(saa716x);
+
+ saa716x_ff_osd_exit(saa716x);
+
+ saa716x_ff_audio_exit(saa716x);
+
+ saa716x_ff_video_exit(saa716x);
+
+ saa716x_dvb_exit(saa716x);
+
+ SAA716x_EPWR(MSI, MSI_INT_ENA_CLR_H, MSI_INT_EXTINT_0);
+
+ /* disable board power */
+ saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_POWER_ENABLE, 0);
+
+ vfree(sti7109->iobuf);
+
+ saa716x->priv = NULL;
+ kfree(sti7109);
+
+ saa716x_i2c_exit(saa716x);
+ saa716x_pci_exit(saa716x);
+ kfree(saa716x);
+}
+
+static void demux_worker(unsigned long data)
+{
+ struct saa716x_fgpi_stream_port *fgpi_entry = (struct saa716x_fgpi_stream_port *)data;
+ struct saa716x_dev *saa716x = fgpi_entry->saa716x;
+ struct dvb_demux *demux;
+ u32 fgpi_index;
+ u32 i;
+ u32 write_index;
+
+ fgpi_index = fgpi_entry->dma_channel - 6;
+ demux = NULL;
+ for (i = 0; i < saa716x->config->adapters; i++) {
+ if (saa716x->config->adap_config[i].ts_port == fgpi_index) {
+ demux = &saa716x->saa716x_adap[i].demux;
+ break;
+ }
+ }
+ if (demux == NULL) {
+ printk(KERN_ERR "%s: unexpected channel %u\n",
+ __func__, fgpi_entry->dma_channel);
+ return;
+ }
+
+ write_index = saa716x_fgpi_get_write_index(saa716x, fgpi_index);
+ if (write_index < 0)
+ return;
+
+ dprintk(SAA716x_DEBUG, 1, "dma buffer = %d", write_index);
+
+ if (write_index == fgpi_entry->read_index) {
+ printk(KERN_DEBUG "%s: called but nothing to do\n", __func__);
+ return;
+ }
+
+ do {
+ u8 *data = (u8 *)fgpi_entry->dma_buf[fgpi_entry->read_index].mem_virt;
+
+ pci_dma_sync_sg_for_cpu(saa716x->pdev,
+ fgpi_entry->dma_buf[fgpi_entry->read_index].sg_list,
+ fgpi_entry->dma_buf[fgpi_entry->read_index].list_len,
+ PCI_DMA_FROMDEVICE);
+
+ dvb_dmx_swfilter(demux, data, 348 * 188);
+
+ fgpi_entry->read_index = (fgpi_entry->read_index + 1) & 7;
+ } while (write_index != fgpi_entry->read_index);
+}
+
+static irqreturn_t saa716x_ff_pci_irq(int irq, void *dev_id)
+{
+ struct saa716x_dev *saa716x = (struct saa716x_dev *) dev_id;
+ struct sti7109_dev *sti7109;
+ u32 msiStatusL;
+ u32 msiStatusH;
+ u32 phiISR;
+
+ if (unlikely(saa716x == NULL)) {
+ printk("%s: saa716x=NULL", __func__);
+ return IRQ_NONE;
+ }
+ sti7109 = saa716x->priv;
+ if (unlikely(sti7109 == NULL)) {
+ printk("%s: sti7109=NULL", __func__);
+ return IRQ_NONE;
+ }
+ if (sti7109->int_count_enable)
+ sti7109->total_int_count++;
+#if 0
+ dprintk(SAA716x_DEBUG, 1, "VI STAT 0=<%02x> 1=<%02x>, CTL 1=<%02x> 2=<%02x>",
+ SAA716x_EPRD(VI0, INT_STATUS),
+ SAA716x_EPRD(VI1, INT_STATUS),
+ SAA716x_EPRD(VI0, INT_ENABLE),
+ SAA716x_EPRD(VI1, INT_ENABLE));
+
+ dprintk(SAA716x_DEBUG, 1, "FGPI STAT 0=<%02x> 1=<%02x>, CTL 1=<%02x> 2=<%02x>",
+ SAA716x_EPRD(FGPI0, INT_STATUS),
+ SAA716x_EPRD(FGPI1, INT_STATUS),
+ SAA716x_EPRD(FGPI0, INT_ENABLE),
+ SAA716x_EPRD(FGPI0, INT_ENABLE));
+
+ dprintk(SAA716x_DEBUG, 1, "FGPI STAT 2=<%02x> 3=<%02x>, CTL 2=<%02x> 3=<%02x>",
+ SAA716x_EPRD(FGPI2, INT_STATUS),
+ SAA716x_EPRD(FGPI3, INT_STATUS),
+ SAA716x_EPRD(FGPI2, INT_ENABLE),
+ SAA716x_EPRD(FGPI3, INT_ENABLE));
+
+ dprintk(SAA716x_DEBUG, 1, "AI STAT 0=<%02x> 1=<%02x>, CTL 0=<%02x> 1=<%02x>",
+ SAA716x_EPRD(AI0, AI_STATUS),
+ SAA716x_EPRD(AI1, AI_STATUS),
+ SAA716x_EPRD(AI0, AI_CTL),
+ SAA716x_EPRD(AI1, AI_CTL));
+
+ dprintk(SAA716x_DEBUG, 1, "MSI STAT L=<%02x> H=<%02x>, CTL L=<%02x> H=<%02x>",
+ SAA716x_EPRD(MSI, MSI_INT_STATUS_L),
+ SAA716x_EPRD(MSI, MSI_INT_STATUS_H),
+ SAA716x_EPRD(MSI, MSI_INT_ENA_L),
+ SAA716x_EPRD(MSI, MSI_INT_ENA_H));
+
+ dprintk(SAA716x_DEBUG, 1, "I2C STAT 0=<%02x> 1=<%02x>, CTL 0=<%02x> 1=<%02x>",
+ SAA716x_EPRD(I2C_A, INT_STATUS),
+ SAA716x_EPRD(I2C_B, INT_STATUS),
+ SAA716x_EPRD(I2C_A, INT_ENABLE),
+ SAA716x_EPRD(I2C_B, INT_ENABLE));
+
+ dprintk(SAA716x_DEBUG, 1, "DCS STAT=<%02x>, CTL=<%02x>",
+ SAA716x_EPRD(DCS, DCSC_INT_STATUS),
+ SAA716x_EPRD(DCS, DCSC_INT_ENABLE));
+#endif
+ msiStatusL = SAA716x_EPRD(MSI, MSI_INT_STATUS_L);
+ SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_L, msiStatusL);
+ msiStatusH = SAA716x_EPRD(MSI, MSI_INT_STATUS_H);
+ SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_H, msiStatusH);
+
+ if (msiStatusL) {
+ if (msiStatusL & MSI_INT_TAGACK_FGPI_2) {
+ if (sti7109->int_count_enable)
+ sti7109->fgpi_int_count[0]++;
+ tasklet_schedule(&saa716x->fgpi[2].tasklet);
+ }
+ if (msiStatusL & MSI_INT_TAGACK_FGPI_3) {
+ if (sti7109->int_count_enable)
+ sti7109->fgpi_int_count[1]++;
+ tasklet_schedule(&saa716x->fgpi[3].tasklet);
+ }
+ }
+ if (msiStatusH) {
+ //dprintk(SAA716x_INFO, 1, "msiStatusH: %08X", msiStatusH);
+ }
+
+ if (msiStatusH & MSI_INT_I2CINT_0) {
+ if (sti7109->int_count_enable)
+ sti7109->i2c_int_count[0]++;
+ saa716x->i2c[0].i2c_op = 0;
+ wake_up(&saa716x->i2c[0].i2c_wq);
+ }
+ if (msiStatusH & MSI_INT_I2CINT_1) {
+ if (sti7109->int_count_enable)
+ sti7109->i2c_int_count[1]++;
+ saa716x->i2c[1].i2c_op = 0;
+ wake_up(&saa716x->i2c[1].i2c_wq);
+ }
+
+ if (msiStatusH & MSI_INT_EXTINT_0) {
+
+ phiISR = SAA716x_EPRD(PHI_1, FPGA_ADDR_EMI_ISR);
+ //dprintk(SAA716x_INFO, 1, "interrupt status register: %08X", phiISR);
+
+ if (sti7109->int_count_enable) {
+ int i;
+ sti7109->ext_int_total_count++;
+ for (i = 0; i < 16; i++)
+ if (phiISR & (1 << i))
+ sti7109->ext_int_source_count[i]++;
+ }
+
+ if (phiISR & ISR_CMD_MASK) {
+
+ u32 value;
+ u32 length;
+ /*dprintk(SAA716x_INFO, 1, "CMD interrupt source");*/
+
+ value = SAA716x_EPRD(PHI_1, ADDR_CMD_DATA);
+ value = __cpu_to_be32(value);
+ length = (value >> 16) + 2;
+
+ /*dprintk(SAA716x_INFO, 1, "CMD length: %d", length);*/
+
+ if (length > MAX_RESULT_LEN) {
+ dprintk(SAA716x_ERROR, 1, "CMD length %d > %d", length, MAX_RESULT_LEN);
+ length = MAX_RESULT_LEN;
+ }
+
+ saa716x_phi_read(saa716x, ADDR_CMD_DATA, sti7109->result_data, length);
+ sti7109->result_len = length;
+ sti7109->result_avail = 1;
+ wake_up(&sti7109->result_avail_wq);
+
+ phiISR &= ~ISR_CMD_MASK;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_CMD_MASK);
+ }
+
+ if (phiISR & ISR_READY_MASK) {
+ /*dprintk(SAA716x_INFO, 1, "READY interrupt source");*/
+ sti7109->cmd_ready = 1;
+ wake_up(&sti7109->cmd_ready_wq);
+ phiISR &= ~ISR_READY_MASK;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_READY_MASK);
+ }
+
+ if (phiISR & ISR_OSD_CMD_MASK) {
+
+ u32 value;
+ u32 length;
+ /*dprintk(SAA716x_INFO, 1, "OSD CMD interrupt source");*/
+
+ value = SAA716x_EPRD(PHI_1, ADDR_OSD_CMD_DATA);
+ value = __cpu_to_be32(value);
+ length = (value >> 16) + 2;
+
+ /*dprintk(SAA716x_INFO, 1, "OSD CMD length: %d", length);*/
+
+ if (length > MAX_RESULT_LEN) {
+ dprintk(SAA716x_ERROR, 1, "OSD CMD length %d > %d", length, MAX_RESULT_LEN);
+ length = MAX_RESULT_LEN;
+ }
+
+ saa716x_phi_read(saa716x, ADDR_OSD_CMD_DATA, sti7109->osd_result_data, length);
+ sti7109->osd_result_len = length;
+ sti7109->osd_result_avail = 1;
+ wake_up(&sti7109->osd_result_avail_wq);
+
+ phiISR &= ~ISR_OSD_CMD_MASK;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_OSD_CMD_MASK);
+ }
+
+ if (phiISR & ISR_OSD_READY_MASK) {
+ /*dprintk(SAA716x_INFO, 1, "OSD_READY interrupt source");*/
+ sti7109->osd_cmd_ready = 1;
+ wake_up(&sti7109->osd_cmd_ready_wq);
+ phiISR &= ~ISR_OSD_READY_MASK;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_OSD_READY_MASK);
+ }
+
+ if (phiISR & ISR_BLOCK_MASK) {
+ /*dprintk(SAA716x_INFO, 1, "BLOCK interrupt source");*/
+ sti7109->block_done = 1;
+ wake_up(&sti7109->block_done_wq);
+ phiISR &= ~ISR_BLOCK_MASK;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_BLOCK_MASK);
+ }
+
+ if (phiISR & ISR_DATA_MASK) {
+ /*dprintk(SAA716x_INFO, 1, "DATA interrupt source");*/
+ sti7109->data_ready = 1;
+ wake_up(&sti7109->data_ready_wq);
+ phiISR &= ~ISR_DATA_MASK;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_DATA_MASK);
+ }
+
+ if (phiISR & ISR_BOOT_FINISH_MASK) {
+ /*dprintk(SAA716x_INFO, 1, "BOOT FINISH interrupt source");*/
+ sti7109->boot_finished = 1;
+ wake_up(&sti7109->boot_finish_wq);
+ phiISR &= ~ISR_BOOT_FINISH_MASK;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_BOOT_FINISH_MASK);
+ }
+
+ if (phiISR & ISR_AUDIO_PTS_MASK) {
+ u8 data[8];
+
+ saa716x_phi_read(saa716x, ADDR_AUDIO_PTS, data, 8);
+ sti7109->audio_pts = (((u64) data[3] & 0x01) << 32)
+ | ((u64) data[4] << 24)
+ | ((u64) data[5] << 16)
+ | ((u64) data[6] << 8)
+ | ((u64) data[7]);
+
+ phiISR &= ~ISR_AUDIO_PTS_MASK;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_AUDIO_PTS_MASK);
+
+ /*dprintk(SAA716x_INFO, 1, "AUDIO PTS: %llX", sti7109->audio_pts);*/
+ }
+
+ if (phiISR & ISR_VIDEO_PTS_MASK) {
+ u8 data[8];
+
+ saa716x_phi_read(saa716x, ADDR_VIDEO_PTS, data, 8);
+ sti7109->video_pts = (((u64) data[3] & 0x01) << 32)
+ | ((u64) data[4] << 24)
+ | ((u64) data[5] << 16)
+ | ((u64) data[6] << 8)
+ | ((u64) data[7]);
+
+ phiISR &= ~ISR_VIDEO_PTS_MASK;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_VIDEO_PTS_MASK);
+
+ /*dprintk(SAA716x_INFO, 1, "VIDEO PTS: %llX", sti7109->video_pts);*/
+ }
+
+ if (phiISR & ISR_CURRENT_STC_MASK) {
+ u8 data[8];
+
+ saa716x_phi_read(saa716x, ADDR_CURRENT_STC, data, 8);
+ sti7109->current_stc = (((u64) data[3] & 0x01) << 32)
+ | ((u64) data[4] << 24)
+ | ((u64) data[5] << 16)
+ | ((u64) data[6] << 8)
+ | ((u64) data[7]);
+
+ phiISR &= ~ISR_CURRENT_STC_MASK;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_CURRENT_STC_MASK);
+
+ /*dprintk(SAA716x_INFO, 1, "CURRENT STC: %llu", sti7109->current_stc);*/
+ }
+
+ if (phiISR & ISR_REMOTE_EVENT_MASK) {
+ u8 data[4];
+ u32 remote_event;
+
+ saa716x_phi_read(saa716x, ADDR_REMOTE_EVENT, data, 4);
+ remote_event = (data[3] << 24)
+ | (data[2] << 16)
+ | (data[1] << 8)
+ | (data[0]);
+ memset(data, 0, sizeof(data));
+ saa716x_phi_write(saa716x, ADDR_REMOTE_EVENT, data, 4);
+
+ phiISR &= ~ISR_REMOTE_EVENT_MASK;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_REMOTE_EVENT_MASK);
+
+ if (remote_event == 0) {
+ dprintk(SAA716x_ERROR, 1, "REMOTE EVENT: %X ignored", remote_event);
+ } else {
+ dprintk(SAA716x_INFO, 1, "REMOTE EVENT: %X", remote_event);
+ saa716x_ir_handler(saa716x, remote_event);
+ }
+ }
+
+ if (phiISR & ISR_DVO_FORMAT_MASK) {
+ u8 data[4];
+ u32 format;
+
+ saa716x_phi_read(saa716x, ADDR_DVO_FORMAT, data, 4);
+ format = (data[0] << 24)
+ | (data[1] << 16)
+ | (data[2] << 8)
+ | (data[3]);
+
+ phiISR &= ~ISR_DVO_FORMAT_MASK;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_DVO_FORMAT_MASK);
+
+ dprintk(SAA716x_INFO, 1, "DVO FORMAT CHANGE: %u", format);
+ }
+
+ if (phiISR & ISR_LOG_MESSAGE_MASK) {
+ char message[SIZE_LOG_MESSAGE_DATA];
+
+ saa716x_phi_read(saa716x, ADDR_LOG_MESSAGE, message,
+ SIZE_LOG_MESSAGE_DATA);
+
+ phiISR &= ~ISR_LOG_MESSAGE_MASK;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_LOG_MESSAGE_MASK);
+
+ dprintk(SAA716x_INFO, 1, "LOG MESSAGE: %.*s",
+ SIZE_LOG_MESSAGE_DATA, message);
+ }
+
+ if (phiISR & ISR_FIFO1_EMPTY_MASK) {
+ u32 fifoCtrl;
+
+ /*dprintk(SAA716x_INFO, 1, "FIFO EMPTY interrupt source");*/
+ fifoCtrl = SAA716x_EPRD(PHI_1, FPGA_ADDR_FIFO_CTRL);
+ fifoCtrl &= ~0x4;
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_FIFO_CTRL, fifoCtrl);
+ tasklet_schedule(&sti7109->fifo_tasklet);
+ phiISR &= ~ISR_FIFO1_EMPTY_MASK;
+ }
+
+ if (phiISR) {
+ dprintk(SAA716x_INFO, 1, "unknown interrupt source");
+ SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, phiISR);
+ }
+ }
+
+ if (sti7109->int_count_enable) {
+ if (jiffies - sti7109->last_int_ticks >= HZ) {
+ dprintk(SAA716x_INFO, 1, "int count: t: %d, f:%d %d, i:%d %d,"
+ "e: %d (%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d)",
+ sti7109->total_int_count,
+ sti7109->fgpi_int_count[0],
+ sti7109->fgpi_int_count[1],
+ sti7109->i2c_int_count[0],
+ sti7109->i2c_int_count[1],
+ sti7109->ext_int_total_count,
+ sti7109->ext_int_source_count[0],
+ sti7109->ext_int_source_count[1],
+ sti7109->ext_int_source_count[2],
+ sti7109->ext_int_source_count[3],
+ sti7109->ext_int_source_count[4],
+ sti7109->ext_int_source_count[5],
+ sti7109->ext_int_source_count[6],
+ sti7109->ext_int_source_count[7],
+ sti7109->ext_int_source_count[8],
+ sti7109->ext_int_source_count[9],
+ sti7109->ext_int_source_count[10],
+ sti7109->ext_int_source_count[11],
+ sti7109->ext_int_source_count[12],
+ sti7109->ext_int_source_count[13],
+ sti7109->ext_int_source_count[14],
+ sti7109->ext_int_source_count[15]);
+ sti7109->total_int_count = 0;
+ memset(sti7109->fgpi_int_count, 0, sizeof(sti7109->fgpi_int_count));
+ memset(sti7109->i2c_int_count, 0, sizeof(sti7109->i2c_int_count));
+ sti7109->ext_int_total_count = 0;
+ memset(sti7109->ext_int_source_count, 0, sizeof(sti7109->ext_int_source_count));
+ sti7109->last_int_ticks = jiffies;
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+#define SAA716x_MODEL_S2_6400_DUAL "Technotrend S2 6400 Dual S2 Premium"
+#define SAA716x_DEV_S2_6400_DUAL "2x DVB-S/S2 + Hardware decode"
+
+static struct stv090x_config tt6400_stv090x_config = {
+ .device = STV0900,
+ .demod_mode = STV090x_DUAL,
+ .clk_mode = STV090x_CLK_EXT,
+
+ .xtal = 13500000,
+ .address = 0x68,
+
+ .ts1_mode = STV090x_TSMODE_SERIAL_CONTINUOUS,
+ .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS,
+ .ts1_clk = 135000000,
+ .ts2_clk = 135000000,
+
+ .repeater_level = STV090x_RPTLEVEL_16,
+
+ .tuner_init = NULL,
+ .tuner_set_mode = NULL,
+ .tuner_set_frequency = NULL,
+ .tuner_get_frequency = NULL,
+ .tuner_set_bandwidth = NULL,
+ .tuner_get_bandwidth = NULL,
+ .tuner_set_bbgain = NULL,
+ .tuner_get_bbgain = NULL,
+ .tuner_set_refclk = NULL,
+ .tuner_get_status = NULL,
+};
+
+static struct stv6110x_config tt6400_stv6110x_config = {
+ .addr = 0x60,
+ .refclk = 27000000,
+ .clk_div = 2,
+};
+
+static struct isl6423_config tt6400_isl6423_config[2] = {
+ {
+ .current_max = SEC_CURRENT_515m,
+ .curlim = SEC_CURRENT_LIM_ON,
+ .mod_extern = 1,
+ .addr = 0x09,
+ },
+ {
+ .current_max = SEC_CURRENT_515m,
+ .curlim = SEC_CURRENT_LIM_ON,
+ .mod_extern = 1,
+ .addr = 0x08,
+ }
+};
+
+
+static int saa716x_s26400_frontend_attach(struct saa716x_adapter *adapter, int count)
+{
+ struct saa716x_dev *saa716x = adapter->saa716x;
+ struct saa716x_i2c *i2c = saa716x->i2c;
+ struct i2c_adapter *i2c_adapter = &i2c[SAA716x_I2C_BUS_A].i2c_adapter;
+
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", count);
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device);
+
+ if (count == 0 || count == 1) {
+ adapter->fe = dvb_attach(stv090x_attach,
+ &tt6400_stv090x_config,
+ i2c_adapter,
+ STV090x_DEMODULATOR_0 + count);
+
+ if (adapter->fe) {
+ struct stv6110x_devctl *ctl;
+ ctl = dvb_attach(stv6110x_attach,
+ adapter->fe,
+ &tt6400_stv6110x_config,
+ i2c_adapter);
+
+ tt6400_stv090x_config.tuner_init = ctl->tuner_init;
+ tt6400_stv090x_config.tuner_sleep = ctl->tuner_sleep;
+ tt6400_stv090x_config.tuner_set_mode = ctl->tuner_set_mode;
+ tt6400_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
+ tt6400_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
+ tt6400_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+ tt6400_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+ tt6400_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain;
+ tt6400_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain;
+ tt6400_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk;
+ tt6400_stv090x_config.tuner_get_status = ctl->tuner_get_status;
+
+ if (count == 1) {
+ /* call the init function once to initialize
+ tuner's clock output divider and demod's
+ master clock */
+ /* The second tuner drives the STV0900 so
+ call it only for adapter 1 */
+ if (adapter->fe->ops.init)
+ adapter->fe->ops.init(adapter->fe);
+ }
+
+ dvb_attach(isl6423_attach,
+ adapter->fe,
+ i2c_adapter,
+ &tt6400_isl6423_config[count]);
+
+ }
+ }
+ return 0;
+}
+
+static struct saa716x_config saa716x_s26400_config = {
+ .model_name = SAA716x_MODEL_S2_6400_DUAL,
+ .dev_type = SAA716x_DEV_S2_6400_DUAL,
+ .boot_mode = SAA716x_EXT_BOOT,
+ .adapters = 2,
+ .frontend_attach = saa716x_s26400_frontend_attach,
+ .irq_handler = saa716x_ff_pci_irq,
+ .i2c_rate = SAA716x_I2C_RATE_100,
+ .i2c_mode = SAA716x_I2C_MODE_IRQ_BUFFERED,
+
+ .adap_config = {
+ {
+ /* Adapter 0 */
+ .ts_port = 2,
+ .worker = demux_worker
+ },{
+ /* Adapter 1 */
+ .ts_port = 3,
+ .worker = demux_worker
+ }
+ }
+};
+
+
+static struct pci_device_id saa716x_ff_pci_table[] = {
+
+ MAKE_ENTRY(TECHNOTREND, S2_6400_DUAL_S2_PREMIUM_DEVEL, SAA7160, &saa716x_s26400_config), /* S2 6400 Dual development version */
+ MAKE_ENTRY(TECHNOTREND, S2_6400_DUAL_S2_PREMIUM_PROD, SAA7160, &saa716x_s26400_config), /* S2 6400 Dual production version */
+ { }
+};
+MODULE_DEVICE_TABLE(pci, saa716x_ff_pci_table);
+
+static struct pci_driver saa716x_ff_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = saa716x_ff_pci_table,
+ .probe = saa716x_ff_pci_probe,
+ .remove = saa716x_ff_pci_remove,
+};
+
+static int saa716x_ff_init(void)
+{
+ return pci_register_driver(&saa716x_ff_pci_driver);
+}
+
+static void saa716x_ff_exit(void)
+{
+ return pci_unregister_driver(&saa716x_ff_pci_driver);
+}
+
+module_init(saa716x_ff_init);
+module_exit(saa716x_ff_exit);
+
+MODULE_DESCRIPTION("SAA716x FF driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/saa716x/saa716x_fgpi.c b/drivers/media/common/saa716x/saa716x_fgpi.c
new file mode 100644
index 0000000..8bdb13d
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_fgpi.c
@@ -0,0 +1,389 @@
+#include <linux/kernel.h>
+
+#include "saa716x_mod.h"
+
+#include "saa716x_fgpi_reg.h"
+#include "saa716x_dma_reg.h"
+#include "saa716x_msi_reg.h"
+
+#include "saa716x_dma.h"
+#include "saa716x_fgpi.h"
+#include "saa716x_spi.h"
+#include "saa716x_priv.h"
+
+static const u32 mmu_pta_base[] = {
+ MMU_PTA_BASE0,
+ MMU_PTA_BASE1,
+ MMU_PTA_BASE2,
+ MMU_PTA_BASE3,
+ MMU_PTA_BASE4,
+ MMU_PTA_BASE5,
+ MMU_PTA_BASE6,
+ MMU_PTA_BASE7,
+ MMU_PTA_BASE8,
+ MMU_PTA_BASE9,
+ MMU_PTA_BASE10,
+ MMU_PTA_BASE11,
+ MMU_PTA_BASE12,
+ MMU_PTA_BASE13,
+ MMU_PTA_BASE14,
+ MMU_PTA_BASE15,
+};
+
+static const u32 mmu_dma_cfg[] = {
+ MMU_DMA_CONFIG0,
+ MMU_DMA_CONFIG1,
+ MMU_DMA_CONFIG2,
+ MMU_DMA_CONFIG3,
+ MMU_DMA_CONFIG4,
+ MMU_DMA_CONFIG5,
+ MMU_DMA_CONFIG6,
+ MMU_DMA_CONFIG7,
+ MMU_DMA_CONFIG8,
+ MMU_DMA_CONFIG9,
+ MMU_DMA_CONFIG10,
+ MMU_DMA_CONFIG11,
+ MMU_DMA_CONFIG12,
+ MMU_DMA_CONFIG13,
+ MMU_DMA_CONFIG14,
+ MMU_DMA_CONFIG15,
+};
+
+static const u32 fgpi_ch[] = {
+ FGPI0,
+ FGPI1,
+ FGPI2,
+ FGPI3
+};
+
+static const u32 bamdma_bufmode[] = {
+ BAM_FGPI0_DMA_BUF_MODE,
+ BAM_FGPI1_DMA_BUF_MODE,
+ BAM_FGPI2_DMA_BUF_MODE,
+ BAM_FGPI3_DMA_BUF_MODE
+};
+
+static const u32 msi_int_tagack[] = {
+ MSI_INT_TAGACK_FGPI_0,
+ MSI_INT_TAGACK_FGPI_1,
+ MSI_INT_TAGACK_FGPI_2,
+ MSI_INT_TAGACK_FGPI_3
+};
+
+static const u32 msi_int_ovrflw[] = {
+ MSI_INT_OVRFLW_FGPI_0,
+ MSI_INT_OVRFLW_FGPI_1,
+ MSI_INT_OVRFLW_FGPI_2,
+ MSI_INT_OVRFLW_FGPI_3
+};
+
+static const u32 msi_int_avint[] = {
+ MSI_INT_AVINT_FGPI_0,
+ MSI_INT_AVINT_FGPI_1,
+ MSI_INT_AVINT_FGPI_2,
+ MSI_INT_AVINT_FGPI_3
+};
+
+void saa716x_fgpiint_disable(struct saa716x_dmabuf *dmabuf, int channel)
+{
+ struct saa716x_dev *saa716x = dmabuf->saa716x;
+
+ u32 fgpi_port;
+
+ fgpi_port = fgpi_ch[channel];
+
+ SAA716x_EPWR(fgpi_port, INT_ENABLE, 0); /* disable FGPI IRQ */
+ SAA716x_EPWR(fgpi_port, INT_CLR_STATUS, 0x7f); /* clear status */
+}
+EXPORT_SYMBOL_GPL(saa716x_fgpiint_disable);
+
+int saa716x_fgpi_get_write_index(struct saa716x_dev *saa716x, u32 fgpi_index)
+{
+ u32 fgpi_base;
+ u32 buf_mode_reg;
+ u32 buf_mode;
+
+ switch (fgpi_index) {
+ case 0: /* FGPI_0 */
+ fgpi_base = FGPI0;
+ buf_mode_reg = BAM_FGPI0_DMA_BUF_MODE;
+ break;
+
+ case 1: /* FGPI_1 */
+ fgpi_base = FGPI1;
+ buf_mode_reg = BAM_FGPI1_DMA_BUF_MODE;
+ break;
+
+ case 2: /* FGPI_2 */
+ fgpi_base = FGPI2;
+ buf_mode_reg = BAM_FGPI2_DMA_BUF_MODE;
+ break;
+
+ case 3: /* FGPI_3 */
+ fgpi_base = FGPI3;
+ buf_mode_reg = BAM_FGPI3_DMA_BUF_MODE;
+ break;
+
+ default:
+ printk(KERN_ERR "%s: unexpected fgpi %u\n",
+ __func__, fgpi_index);
+ return -1;
+ }
+
+ buf_mode = SAA716x_EPRD(BAM, buf_mode_reg);
+ if (saa716x->revision < 2) {
+ /* workaround for revision 1: restore buffer numbers on BAM */
+ SAA716x_EPWR(fgpi_base, INT_CLR_STATUS, 0x7F);
+ SAA716x_EPWR(BAM, buf_mode_reg, buf_mode | 7);
+ }
+ return (buf_mode >> 3) & 0x7;
+}
+EXPORT_SYMBOL_GPL(saa716x_fgpi_get_write_index);
+
+static u32 saa716x_init_ptables(struct saa716x_dmabuf *dmabuf, int channel)
+{
+ struct saa716x_dev *saa716x = dmabuf->saa716x;
+
+ u32 config, i;
+
+ for (i = 0; i < FGPI_BUFFERS; i++)
+ BUG_ON((dmabuf[i].mem_ptab_phys == 0));
+
+ config = mmu_dma_cfg[channel]; /* DMACONFIGx */
+
+ SAA716x_EPWR(MMU, config, (FGPI_BUFFERS - 1));
+ SAA716x_EPWR(MMU, MMU_PTA0_LSB(channel), PTA_LSB(dmabuf[0].mem_ptab_phys)); /* Low */
+ SAA716x_EPWR(MMU, MMU_PTA0_MSB(channel), PTA_MSB(dmabuf[0].mem_ptab_phys)); /* High */
+ SAA716x_EPWR(MMU, MMU_PTA1_LSB(channel), PTA_LSB(dmabuf[1].mem_ptab_phys)); /* Low */
+ SAA716x_EPWR(MMU, MMU_PTA1_MSB(channel), PTA_MSB(dmabuf[1].mem_ptab_phys)); /* High */
+ SAA716x_EPWR(MMU, MMU_PTA2_LSB(channel), PTA_LSB(dmabuf[2].mem_ptab_phys)); /* Low */
+ SAA716x_EPWR(MMU, MMU_PTA2_MSB(channel), PTA_MSB(dmabuf[2].mem_ptab_phys)); /* High */
+ SAA716x_EPWR(MMU, MMU_PTA3_LSB(channel), PTA_LSB(dmabuf[3].mem_ptab_phys)); /* Low */
+ SAA716x_EPWR(MMU, MMU_PTA3_MSB(channel), PTA_MSB(dmabuf[3].mem_ptab_phys)); /* High */
+ SAA716x_EPWR(MMU, MMU_PTA4_LSB(channel), PTA_LSB(dmabuf[4].mem_ptab_phys)); /* Low */
+ SAA716x_EPWR(MMU, MMU_PTA4_MSB(channel), PTA_MSB(dmabuf[4].mem_ptab_phys)); /* High */
+ SAA716x_EPWR(MMU, MMU_PTA5_LSB(channel), PTA_LSB(dmabuf[5].mem_ptab_phys)); /* Low */
+ SAA716x_EPWR(MMU, MMU_PTA5_MSB(channel), PTA_MSB(dmabuf[5].mem_ptab_phys)); /* High */
+ SAA716x_EPWR(MMU, MMU_PTA6_LSB(channel), PTA_LSB(dmabuf[6].mem_ptab_phys)); /* Low */
+ SAA716x_EPWR(MMU, MMU_PTA6_MSB(channel), PTA_MSB(dmabuf[6].mem_ptab_phys)); /* High */
+ SAA716x_EPWR(MMU, MMU_PTA7_LSB(channel), PTA_LSB(dmabuf[7].mem_ptab_phys)); /* Low */
+ SAA716x_EPWR(MMU, MMU_PTA7_MSB(channel), PTA_MSB(dmabuf[7].mem_ptab_phys)); /* High */
+
+ return 0;
+}
+
+int saa716x_fgpi_setparams(struct saa716x_dmabuf *dmabuf,
+ struct fgpi_stream_params *stream_params,
+ int port)
+{
+ struct saa716x_dev *saa716x = dmabuf->saa716x;
+
+ u32 fgpi_port, buf_mode, val, mid;
+ u32 D1_XY_END, offst_1, offst_2;
+ int i = 0;
+
+ fgpi_port = fgpi_ch[port];
+ buf_mode = bamdma_bufmode[port];
+
+ /* Reset FGPI block */
+ SAA716x_EPWR(fgpi_port, FGPI_SOFT_RESET, FGPI_SOFTWARE_RESET);
+
+ /* Reset DMA channel */
+ SAA716x_EPWR(BAM, buf_mode, 0x00000040);
+ saa716x_init_ptables(dmabuf, saa716x->fgpi[port].dma_channel);
+
+
+ /* monitor BAM reset */
+ val = SAA716x_EPRD(BAM, buf_mode);
+ while (val && (i < 100)) {
+ msleep(30);
+ val = SAA716x_EPRD(BAM, buf_mode);
+ i++;
+ }
+
+ if (val) {
+ dprintk(SAA716x_ERROR, 1, "Error: BAM FGPI Reset failed!");
+ return -EIO;
+ }
+
+ /* set buffer count */
+ SAA716x_EPWR(BAM, buf_mode, FGPI_BUFFERS - 1);
+
+ /* initialize all available address offsets */
+ SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_0(port), 0x0);
+ SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_1(port), 0x0);
+ SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_2(port), 0x0);
+ SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_3(port), 0x0);
+ SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_4(port), 0x0);
+ SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_5(port), 0x0);
+ SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_6(port), 0x0);
+ SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_7(port), 0x0);
+
+ /* get module ID */
+ mid = SAA716x_EPRD(fgpi_port, FGPI_MODULE_ID);
+ if (mid != 0x14b0100)
+ dprintk(SAA716x_ERROR, 1, "FGPI Id<%04x> is not supported", mid);
+
+ /* Initialize FGPI block */
+ SAA716x_EPWR(fgpi_port, FGPI_REC_SIZE, stream_params->samples * (stream_params->bits / 8));
+ SAA716x_EPWR(fgpi_port, FGPI_STRIDE, stream_params->pitch);
+
+ offst_1 = 0;
+ offst_2 = 0;
+ switch (stream_params->stream_type) {
+ case FGPI_TRANSPORT_STREAM:
+ SAA716x_EPWR(fgpi_port, FGPI_CONTROL, 0x00000080);
+ SAA716x_EPWR(fgpi_port, FGPI_SIZE, stream_params->lines);
+ break;
+
+ case FGPI_PROGRAM_STREAM:
+ SAA716x_EPWR(fgpi_port, FGPI_CONTROL, 0x00000088);
+ SAA716x_EPWR(fgpi_port, FGPI_SIZE, stream_params->lines);
+ break;
+
+ case FGPI_VIDEO_STREAM:
+ SAA716x_EPWR(fgpi_port, FGPI_CONTROL, 0x00000088);
+ SAA716x_EPWR(fgpi_port, FGPI_D1_XY_START, 0x00000002);
+
+ if ((stream_params->stream_flags & FGPI_INTERLACED) &&
+ (stream_params->stream_flags & FGPI_ODD_FIELD) &&
+ (stream_params->stream_flags & FGPI_EVEN_FIELD)) {
+
+ SAA716x_EPWR(fgpi_port, FGPI_SIZE, stream_params->lines / 2);
+ SAA716x_EPWR(fgpi_port, FGPI_STRIDE, 768 * 4); /* interlaced stride of 2 lines */
+
+ D1_XY_END = (stream_params->samples << 16);
+ D1_XY_END |= (stream_params->lines / 2) + 2;
+
+ if (stream_params->stream_flags & FGPI_PAL)
+ offst_1 = 768 * 2;
+ else
+ offst_2 = 768 * 2;
+
+ } else {
+ SAA716x_EPWR(fgpi_port, FGPI_SIZE, stream_params->lines);
+ SAA716x_EPWR(fgpi_port, FGPI_STRIDE, 768 * 2); /* stride of 1 line */
+
+ D1_XY_END = stream_params->samples << 16;
+ D1_XY_END |= stream_params->lines + 2;
+ }
+
+ SAA716x_EPWR(fgpi_port, FGPI_D1_XY_END, D1_XY_END);
+ break;
+
+ default:
+ SAA716x_EPWR(fgpi_port, FGPI_CONTROL, 0x00000080);
+ break;
+ }
+
+ SAA716x_EPWR(fgpi_port, FGPI_BASE_1, ((saa716x->fgpi[port].dma_channel) << 21) + offst_1);
+ SAA716x_EPWR(fgpi_port, FGPI_BASE_2, ((saa716x->fgpi[port].dma_channel) << 21) + offst_2);
+
+ return 0;
+}
+
+int saa716x_fgpi_start(struct saa716x_dev *saa716x, int port,
+ struct fgpi_stream_params *stream_params)
+{
+ u32 fgpi_port;
+ u32 config;
+ u32 val;
+ u32 i;
+
+ fgpi_port = fgpi_ch[port];
+
+ SAA716x_EPWR(fgpi_port, FGPI_INTERFACE, 0);
+ msleep(10);
+
+ if (saa716x_fgpi_setparams(saa716x->fgpi[port].dma_buf, stream_params, port) != 0) {
+ return -EIO;
+ }
+
+ config = mmu_dma_cfg[saa716x->fgpi[port].dma_channel]; /* DMACONFIGx */
+
+ val = SAA716x_EPRD(MMU, config);
+ SAA716x_EPWR(MMU, config, val & ~0x40);
+ SAA716x_EPWR(MMU, config, val | 0x40);
+
+ SAA716x_EPWR(fgpi_port, INT_ENABLE, 0x7F);
+
+ val = SAA716x_EPRD(MMU, config);
+ i = 0;
+ while (i < 500) {
+ if (val & 0x80)
+ break;
+ msleep(10);
+ val = SAA716x_EPRD(MMU, config);
+ i++;
+ }
+
+ if (!(val & 0x80)) {
+ dprintk(SAA716x_ERROR, 1, "Error: PTE pre-fetch failed!");
+ return -EIO;
+ }
+
+ val = SAA716x_EPRD(fgpi_port, FGPI_CONTROL);
+ val |= 0x3000;
+
+ saa716x_set_clk_external(saa716x, saa716x->fgpi[port].dma_channel);
+
+ SAA716x_EPWR(fgpi_port, FGPI_CONTROL, val);
+
+ SAA716x_EPWR(MSI, MSI_INT_ENA_SET_L, msi_int_tagack[port]);
+
+ return 0;
+}
+
+int saa716x_fgpi_stop(struct saa716x_dev *saa716x, int port)
+{
+ u32 fgpi_port;
+ u32 val;
+
+ fgpi_port = fgpi_ch[port];
+
+ SAA716x_EPWR(MSI, MSI_INT_ENA_CLR_L, msi_int_tagack[port]);
+
+ val = SAA716x_EPRD(fgpi_port, FGPI_CONTROL);
+ val &= ~0x3000;
+ SAA716x_EPWR(fgpi_port, FGPI_CONTROL, val);
+
+ saa716x_set_clk_internal(saa716x, saa716x->fgpi[port].dma_channel);
+
+ return 0;
+}
+
+int saa716x_fgpi_init(struct saa716x_dev *saa716x, int port,
+ void (*worker)(unsigned long))
+{
+ int i;
+ int ret;
+
+ saa716x->fgpi[port].dma_channel = port + 6;
+ for (i = 0; i < FGPI_BUFFERS; i++)
+ {
+ /* TODO: what is a good size for TS DMA buffer? */
+ ret = saa716x_dmabuf_alloc(saa716x, &saa716x->fgpi[port].dma_buf[i], 16 * SAA716x_PAGE_SIZE);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ saa716x->fgpi[port].saa716x = saa716x;
+ tasklet_init(&saa716x->fgpi[port].tasklet, worker,
+ (unsigned long)&saa716x->fgpi[port]);
+ saa716x->fgpi[port].read_index = 0;
+
+ return 0;
+}
+
+int saa716x_fgpi_exit(struct saa716x_dev *saa716x, int port)
+{
+ int i;
+
+ tasklet_kill(&saa716x->fgpi[port].tasklet);
+ for (i = 0; i < FGPI_BUFFERS; i++)
+ {
+ saa716x_dmabuf_free(saa716x, &saa716x->fgpi[port].dma_buf[i]);
+ }
+
+ return 0;
+}
diff --git a/drivers/media/common/saa716x/saa716x_fgpi.h b/drivers/media/common/saa716x/saa716x_fgpi.h
new file mode 100644
index 0000000..225aff0
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_fgpi.h
@@ -0,0 +1,112 @@
+#ifndef __SAA716x_FGPI_H
+#define __SAA716x_FGPI_H
+
+#include <linux/interrupt.h>
+
+#define FGPI_BUFFERS 8
+#define PTA_LSB(__mem) ((u32 ) (__mem))
+#define PTA_MSB(__mem) ((u32 ) ((u64)(__mem) >> 32))
+
+#define BAM_DMA_BUF_MODE_BASE 0x0d8
+#define BAM_DMA_BUF_MODE_OFFSET 0x24
+
+#define BAM_DMA_BUF_MODE(__ch) (BAM_DMA_BUF_MODE_BASE + (BAM_DMA_BUF_MODE_OFFSET * __ch))
+
+#define BAM_FGPI_ADDR_OFFST_BASE 0x0dc
+#define BAM_FGPI_ADDR_OFFST_OFFSET 0x24
+
+#define BAM_FGPI_ADDR_OFFSET(__ch) (BAM_FGPI_ADDR_OFFST_BASE + (BAM_FGPI_ADDR_OFFST_OFFSET * __ch))
+
+#define BAM_FGPI_ADDR_OFFST_0(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x00
+#define BAM_FGPI_ADDR_OFFST_1(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x04
+#define BAM_FGPI_ADDR_OFFST_2(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x08
+#define BAM_FGPI_ADDR_OFFST_3(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x0c
+#define BAM_FGPI_ADDR_OFFST_4(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x10
+#define BAM_FGPI_ADDR_OFFST_5(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x14
+#define BAM_FGPI_ADDR_OFFST_6(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x18
+#define BAM_FGPI_ADDR_OFFST_7(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x1c
+
+struct saa716x_dmabuf;
+
+/*
+ * Port supported streams
+ *
+ * FGPI_AUDIO_STREAM
+ * FGPI_VIDEO_STREAM
+ * FGPI_VBI_STREAM
+ * FGPI_TRANSPORT_STREAM
+ * FGPI_PROGRAM_STREAM
+ */
+enum fgpi_stream_type {
+ FGPI_AUDIO_STREAM = 0x01,
+ FGPI_VIDEO_STREAM = 0x02,
+ FGPI_VBI_STREAM = 0x04,
+ FGPI_TRANSPORT_STREAM = 0x08,
+ FGPI_PROGRAM_STREAM = 0x10
+};
+
+/*
+ * Stream port flags
+ *
+ * FGPI_ODD_FIELD
+ * FGPI_EVEN_FIELD
+ * FGPI_HD_0
+ * FGPI_HD_1
+ * FGPI_PAL
+ * FGPI_NTSC
+ */
+enum fgpi_stream_flags {
+ FGPI_ODD_FIELD = 0x0001,
+ FGPI_EVEN_FIELD = 0x0002,
+ FGPI_INTERLACED = 0x0004,
+ FGPI_HD0 = 0x0010,
+ FGPI_HD1 = 0x0020,
+ FGPI_PAL = 0x0040,
+ FGPI_NTSC = 0x0080,
+ FGPI_NO_SCALER = 0x0100,
+};
+
+/*
+ * Stream port parameters
+ * bits: Bits per sample
+ * samples: samples perline
+ * lines: number of lines
+ * pitch: stream pitch in bytes
+ * offset: offset to first valid line
+ */
+struct fgpi_stream_params {
+ u32 bits;
+ u32 samples;
+ u32 lines;
+
+ s32 pitch;
+
+ u32 offset;
+ u32 page_tables;
+
+ enum fgpi_stream_flags stream_flags;
+ enum fgpi_stream_type stream_type;
+};
+
+struct saa716x_dmabuf;
+
+struct saa716x_fgpi_stream_port {
+ u8 dma_channel;
+ struct saa716x_dmabuf dma_buf[FGPI_BUFFERS];
+ struct saa716x_dev *saa716x;
+ struct tasklet_struct tasklet;
+ u8 read_index;
+};
+
+extern void saa716x_fgpiint_disable(struct saa716x_dmabuf *dmabuf, int channel);
+extern int saa716x_fgpi_get_write_index(struct saa716x_dev *saa716x,
+ u32 fgpi_index);
+extern int saa716x_fgpi_start(struct saa716x_dev *saa716x, int port,
+ struct fgpi_stream_params *stream_params);
+extern int saa716x_fgpi_stop(struct saa716x_dev *saa716x, int port);
+
+extern int saa716x_fgpi_init(struct saa716x_dev *saa716x, int port,
+ void (*worker)(unsigned long));
+extern int saa716x_fgpi_exit(struct saa716x_dev *saa716x, int port);
+
+#endif /* __SAA716x_FGPI_H */
diff --git a/drivers/media/common/saa716x/saa716x_fgpi_reg.h b/drivers/media/common/saa716x/saa716x_fgpi_reg.h
new file mode 100644
index 0000000..1193016
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_fgpi_reg.h
@@ -0,0 +1,74 @@
+#ifndef __SAA716x_FGPI_REG_H
+#define __SAA716x_FGPI_REG_H
+
+/* -------------- FGPI Registers -------------- */
+
+#define FGPI_CONTROL 0x000
+#define FGPI_CAPTURE_ENABLE_2 (0x00000001 << 13)
+#define FGPI_CAPTURE_ENABLE_1 (0x00000001 << 12)
+#define FGPI_MODE (0x00000001 << 11)
+#define FGPI_SAMPLE_SIZE (0x00000003 << 8)
+#define FGPI_BUF_SYNC_MSG_STOP (0x00000003 << 5)
+#define FGPI_REC_START_MSG_START (0x00000003 << 2)
+#define FGPI_TSTAMP_SELECT (0x00000001 << 1)
+#define FGPI_VAR_LENGTH (0x00000001 << 0)
+
+#define FGPI_BASE_1 0x004
+#define FGPI_BASE_2 0x008
+#define FGPI_SIZE 0x00c
+#define FGPI_REC_SIZE 0x010
+#define FGPI_STRIDE 0x014
+#define FGPI_NUM_RECORD_1 0x018
+#define FGPI_NUM_RECORD_2 0x01c
+#define FGPI_THRESHOLD_1 0x020
+#define FGPI_THRESHOLD_2 0x024
+#define FGPI_D1_XY_START 0x028
+#define FGPI_D1_XY_END 0x02c
+
+#define INT_STATUS 0xfe0
+#define FGPI_BUF1_ACTIVE (0x00000001 << 7)
+#define FGPI_OVERFLOW (0x00000001 << 6)
+#define FGPI_MBE (0x00000001 << 5)
+#define FGPI_UNDERRUN (0x00000001 << 4)
+#define FGPI_THRESH2_REACHED (0x00000001 << 3)
+#define FGPI_THRESH1_REACHED (0x00000001 << 2)
+#define FGPI_BUF2_FULL (0x00000001 << 1)
+#define FGPI_BUF1_FULL (0x00000001 << 0)
+
+#define INT_ENABLE 0xfe4
+#define FGPI_OVERFLOW_ENA (0x00000001 << 6)
+#define FGPI_MBE_ENA (0x00000001 << 5)
+#define FGPI_UNDERRUN_ENA (0x00000001 << 4)
+#define FGPI_THRESH2_REACHED_ENA (0x00000001 << 3)
+#define FGPI_THRESH1_REACHED_ENA (0x00000001 << 2)
+#define FGPI_BUF2_FULL_ENA (0x00000001 << 1)
+#define FGPI_BUF1_FULL_ENA (0x00000001 << 0)
+
+#define INT_CLR_STATUS 0xfe8
+#define FGPI_OVERFLOW_ACK (0x00000001 << 6)
+#define FGPI_MBE_ACK (0x00000001 << 5)
+#define FGPI_UNDERRUN_ACK (0x00000001 << 4)
+#define FGPI_THRESH2_REACHED_ACK (0x00000001 << 3)
+#define FGPI_THRESH1_REACHED_ACK (0x00000001 << 2)
+#define FGPI_BUF2_DONE_ACK (0x00000001 << 1)
+#define FGPI_BUF1_DONE_ACK (0x00000001 << 0)
+
+#define INT_SET_STATUS 0xfec
+#define FGPI_OVERFLOW_SET (0x00000001 << 6)
+#define FGPI_MBE_SET (0x00000001 << 5)
+#define FGPI_UNDERRUN_SET (0x00000001 << 4)
+#define FGPI_THRESH2_REACHED_SET (0x00000001 << 3)
+#define FGPI_THRESH1_REACHED_SET (0x00000001 << 2)
+#define FGPI_BUF2_DONE_SET (0x00000001 << 1)
+#define FGPI_BUF1_DONE_SET (0x00000001 << 0)
+
+#define FGPI_SOFT_RESET 0xff0
+#define FGPI_SOFTWARE_RESET (0x00000001 << 0)
+
+#define FGPI_INTERFACE 0xff4
+#define FGPI_DISABLE_BUS_IF (0x00000001 << 0)
+
+#define FGPI_MOD_ID_EXT 0xff8
+#define FGPI_MODULE_ID 0xffc
+
+#endif /* __SAA716x_FGPI_REG_H */
diff --git a/drivers/media/common/saa716x/saa716x_gpio.c b/drivers/media/common/saa716x/saa716x_gpio.c
new file mode 100644
index 0000000..62b6112
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_gpio.c
@@ -0,0 +1,140 @@
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+
+#include "saa716x_mod.h"
+
+#include "saa716x_gpio_reg.h"
+
+#include "saa716x_gpio.h"
+#include "saa716x_spi.h"
+#include "saa716x_priv.h"
+
+void saa716x_gpio_init(struct saa716x_dev *saa716x)
+{
+ spin_lock_init(&saa716x->gpio_lock);
+}
+EXPORT_SYMBOL_GPL(saa716x_gpio_init);
+
+int saa716x_get_gpio_mode(struct saa716x_dev *saa716x, u32 *config)
+{
+ *config = SAA716x_EPRD(GPIO, GPIO_WR_MODE);
+
+ return 0;
+}
+
+int saa716x_set_gpio_mode(struct saa716x_dev *saa716x, u32 mask, u32 config)
+{
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&saa716x->gpio_lock, flags);
+ reg = SAA716x_EPRD(GPIO, GPIO_WR_MODE);
+ reg &= ~mask;
+ reg |= (config & mask);
+ SAA716x_EPWR(GPIO, GPIO_WR_MODE, reg);
+ spin_unlock_irqrestore(&saa716x->gpio_lock, flags);
+
+ return 0;
+}
+
+u32 saa716x_gpio_rd(struct saa716x_dev *saa716x)
+{
+ return SAA716x_EPRD(GPIO, GPIO_RD);
+}
+
+void saa716x_gpio_wr(struct saa716x_dev *saa716x, u32 data)
+{
+ SAA716x_EPWR(GPIO, GPIO_WR, data);
+}
+
+void saa716x_gpio_ctl(struct saa716x_dev *saa716x, u32 mask, u32 bits)
+{
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&saa716x->gpio_lock, flags);
+
+ reg = SAA716x_EPRD(GPIO, GPIO_OEN);
+ reg &= mask;
+ reg |= bits;
+ SAA716x_EPWR(GPIO, GPIO_OEN, reg);
+
+ spin_unlock_irqrestore(&saa716x->gpio_lock, flags);
+}
+
+void saa716x_gpio_bits(struct saa716x_dev *saa716x, u32 bits)
+{
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&saa716x->gpio_lock, flags);
+
+ reg = SAA716x_EPRD(GPIO, GPIO_WR);
+ reg &= ~bits;
+ /* TODO ! add maskable config bits in here */
+ /* reg |= (config->mask & bits) */
+ reg |= bits;
+ SAA716x_EPWR(GPIO, GPIO_WR, reg);
+
+ spin_unlock_irqrestore(&saa716x->gpio_lock, flags);
+}
+
+void saa716x_gpio_set_output(struct saa716x_dev *saa716x, int gpio)
+{
+ uint32_t value;
+
+ value = SAA716x_EPRD(GPIO, GPIO_OEN);
+ value &= ~(1 << gpio);
+ SAA716x_EPWR(GPIO, GPIO_OEN, value);
+}
+EXPORT_SYMBOL_GPL(saa716x_gpio_set_output);
+
+void saa716x_gpio_set_input(struct saa716x_dev *saa716x, int gpio)
+{
+ uint32_t value;
+
+ value = SAA716x_EPRD(GPIO, GPIO_OEN);
+ value |= 1 << gpio;
+ SAA716x_EPWR(GPIO, GPIO_OEN, value);
+}
+EXPORT_SYMBOL_GPL(saa716x_gpio_set_input);
+
+void saa716x_gpio_set_mode(struct saa716x_dev *saa716x, int gpio, int mode)
+{
+ uint32_t value;
+
+ value = SAA716x_EPRD(GPIO, GPIO_WR_MODE);
+ if (mode)
+ value |= 1 << gpio;
+ else
+ value &= ~(1 << gpio);
+ SAA716x_EPWR(GPIO, GPIO_WR_MODE, value);
+}
+EXPORT_SYMBOL_GPL(saa716x_gpio_set_mode);
+
+void saa716x_gpio_write(struct saa716x_dev *saa716x, int gpio, int set)
+{
+ uint32_t value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&saa716x->gpio_lock, flags);
+ value = SAA716x_EPRD(GPIO, GPIO_WR);
+ if (set)
+ value |= 1 << gpio;
+ else
+ value &= ~(1 << gpio);
+ SAA716x_EPWR(GPIO, GPIO_WR, value);
+ spin_unlock_irqrestore(&saa716x->gpio_lock, flags);
+}
+EXPORT_SYMBOL_GPL(saa716x_gpio_write);
+
+int saa716x_gpio_read(struct saa716x_dev *saa716x, int gpio)
+{
+ uint32_t value;
+
+ value = SAA716x_EPRD(GPIO, GPIO_RD);
+ if (value & (1 << gpio))
+ return 1;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa716x_gpio_read);
diff --git a/drivers/media/common/saa716x/saa716x_gpio.h b/drivers/media/common/saa716x/saa716x_gpio.h
new file mode 100644
index 0000000..a82580b
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_gpio.h
@@ -0,0 +1,26 @@
+#ifndef __SAA716x_GPIO_H
+#define __SAA716x_GPIO_H
+
+#define BOOT_MODE GPIO_31 | GPIO_30
+#define AV_UNIT_B GPIO_25
+#define AV_UNIT_A GPIO_24
+#define AV_INTR_B GPIO_01
+#define AV_INTR_A GPIO_00
+
+struct saa716x_dev;
+
+extern void saa716x_gpio_init(struct saa716x_dev *saa716x);
+
+extern u32 saa716x_gpio_rd(struct saa716x_dev *saa716x);
+extern void saa716x_gpio_wr(struct saa716x_dev *saa716x, u32 data);
+extern void saa716x_gpio_ctl(struct saa716x_dev *saa716x, u32 mask, u32 bits);
+
+extern void saa716x_gpio_bits(struct saa716x_dev *saa716x, u32 bits);
+
+extern void saa716x_gpio_set_output(struct saa716x_dev *saa716x, int gpio);
+extern void saa716x_gpio_set_input(struct saa716x_dev *saa716x, int gpio);
+extern void saa716x_gpio_set_mode(struct saa716x_dev *saa716x, int gpio, int mode);
+extern void saa716x_gpio_write(struct saa716x_dev *saa716x, int gpio, int set);
+extern int saa716x_gpio_read(struct saa716x_dev *saa716x, int gpio);
+
+#endif /* __SAA716x_GPIO_H */
diff --git a/drivers/media/common/saa716x/saa716x_gpio_reg.h b/drivers/media/common/saa716x/saa716x_gpio_reg.h
new file mode 100644
index 0000000..f36184a
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_gpio_reg.h
@@ -0,0 +1,47 @@
+#ifndef __SAA716x_GPIO_REG_H
+#define __SAA716x_GPIO_REG_H
+
+/* -------------- GPIO Registers -------------- */
+
+#define GPIO_RD 0x000
+#define GPIO_WR 0x004
+#define GPIO_WR_MODE 0x008
+#define GPIO_OEN 0x00c
+
+#define GPIO_SW_RST 0xff0
+#define GPIO_SW_RESET (0x00000001 << 0)
+
+#define GPIO_31 (1 << 31)
+#define GPIO_30 (1 << 30)
+#define GPIO_29 (1 << 29)
+#define GPIO_28 (1 << 28)
+#define GPIO_27 (1 << 27)
+#define GPIO_26 (1 << 26)
+#define GPIO_25 (1 << 25)
+#define GPIO_24 (1 << 24)
+#define GPIO_23 (1 << 23)
+#define GPIO_22 (1 << 22)
+#define GPIO_21 (1 << 21)
+#define GPIO_20 (1 << 20)
+#define GPIO_19 (1 << 19)
+#define GPIO_18 (1 << 18)
+#define GPIO_17 (1 << 17)
+#define GPIO_16 (1 << 16)
+#define GPIO_15 (1 << 15)
+#define GPIO_14 (1 << 14)
+#define GPIO_13 (1 << 13)
+#define GPIO_12 (1 << 12)
+#define GPIO_11 (1 << 11)
+#define GPIO_10 (1 << 10)
+#define GPIO_09 (1 << 9)
+#define GPIO_08 (1 << 8)
+#define GPIO_07 (1 << 7)
+#define GPIO_06 (1 << 6)
+#define GPIO_05 (1 << 5)
+#define GPIO_04 (1 << 4)
+#define GPIO_03 (1 << 3)
+#define GPIO_02 (1 << 2)
+#define GPIO_01 (1 << 1)
+#define GPIO_00 (1 << 0)
+
+#endif /* __SAA716x_GPIO_REG_H */
diff --git a/drivers/media/common/saa716x/saa716x_greg.c b/drivers/media/common/saa716x/saa716x_greg.c
new file mode 100644
index 0000000..d93a3b8
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_greg.c
@@ -0,0 +1,42 @@
+#include <linux/kernel.h>
+
+#include "saa716x_mod.h"
+
+#include "saa716x_greg_reg.h"
+#include "saa716x_greg.h"
+#include "saa716x_spi.h"
+#include "saa716x_priv.h"
+
+static u32 g_save[12];
+
+void saa716x_greg_save(struct saa716x_dev *saa716x)
+{
+ g_save[0] = SAA716x_EPRD(GREG, GREG_SUBSYS_CONFIG);
+ g_save[1] = SAA716x_EPRD(GREG, GREG_MSI_BAR_PMCSR);
+ g_save[2] = SAA716x_EPRD(GREG, GREG_PMCSR_DATA_1);
+ g_save[3] = SAA716x_EPRD(GREG, GREG_PMCSR_DATA_2);
+ g_save[4] = SAA716x_EPRD(GREG, GREG_VI_CTRL);
+ g_save[5] = SAA716x_EPRD(GREG, GREG_FGPI_CTRL);
+ g_save[6] = SAA716x_EPRD(GREG, GREG_RSTU_CTRL);
+ g_save[7] = SAA716x_EPRD(GREG, GREG_I2C_CTRL);
+ g_save[8] = SAA716x_EPRD(GREG, GREG_OVFLW_CTRL);
+ g_save[9] = SAA716x_EPRD(GREG, GREG_TAG_ACK_FLEN);
+
+ g_save[10] = SAA716x_EPRD(GREG, GREG_VIDEO_IN_CTRL);
+}
+
+void saa716x_greg_restore(struct saa716x_dev *saa716x)
+{
+ SAA716x_EPWR(GREG, GREG_SUBSYS_CONFIG, g_save[0]);
+ SAA716x_EPWR(GREG, GREG_MSI_BAR_PMCSR, g_save[1]);
+ SAA716x_EPWR(GREG, GREG_PMCSR_DATA_1, g_save[2]);
+ SAA716x_EPWR(GREG, GREG_PMCSR_DATA_2, g_save[3]);
+ SAA716x_EPWR(GREG, GREG_VI_CTRL, g_save[4]);
+ SAA716x_EPWR(GREG, GREG_FGPI_CTRL, g_save[5]);
+ SAA716x_EPWR(GREG, GREG_RSTU_CTRL, g_save[6]);
+ SAA716x_EPWR(GREG, GREG_I2C_CTRL, g_save[7]);
+ SAA716x_EPWR(GREG, GREG_OVFLW_CTRL, g_save[8]);
+ SAA716x_EPWR(GREG, GREG_TAG_ACK_FLEN, g_save[9]);
+
+ SAA716x_EPWR(GREG, GREG_VIDEO_IN_CTRL, g_save[10]);
+}
diff --git a/drivers/media/common/saa716x/saa716x_greg.h b/drivers/media/common/saa716x/saa716x_greg.h
new file mode 100644
index 0000000..487595e
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_greg.h
@@ -0,0 +1,9 @@
+#ifndef __SAA716x_GREG_H
+#define __SAA716x_GREG_H
+
+struct saa716x_dev;
+
+extern void saa716x_greg_save(struct saa716x_dev *saa716x);
+extern void saa716x_greg_restore(struct saa716x_dev *saa716x);
+
+#endif /* __SAA716x_GREG_H */
diff --git a/drivers/media/common/saa716x/saa716x_greg_reg.h b/drivers/media/common/saa716x/saa716x_greg_reg.h
new file mode 100644
index 0000000..052e8cd
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_greg_reg.h
@@ -0,0 +1,91 @@
+#ifndef __SAA716x_GREG_REG_H
+#define __SAA716x_GREG_REG_H
+
+/* -------------- GREG Registers -------------- */
+
+#define GREG_SUBSYS_CONFIG 0x000
+#define GREG_SUBSYS_ID (0x0000ffff << 16)
+#define GREG_SUBSYS_VID (0x0000ffff << 0)
+
+#define GREG_MSI_BAR_PMCSR 0x004
+#define GREG_PMCSR_SCALE_7 (0x00000003 << 30)
+#define GREG_PMCSR_SCALE_6 (0x00000003 << 28)
+#define GREG_PMCSR_SCALE_5 (0x00000003 << 26)
+#define GREG_PMCSR_SCALE_4 (0x00000003 << 24)
+#define GREG_PMCSR_SCALE_3 (0x00000003 << 22)
+#define GREG_PMCSR_SCALE_2 (0x00000003 << 20)
+#define GREG_PMCSR_SCALE_1 (0x00000003 << 18)
+#define GREG_PMCSR_SCALE_0 (0x00000003 << 16)
+
+#define GREG_BAR_WIDTH_17 (0x0000001e << 8)
+#define GREG_BAR_WIDTH_18 (0x0000001c << 8)
+#define GREG_BAR_WIDTH_19 (0x00000018 << 8)
+#define GREG_BAR_WIDTH_20 (0x00000010 << 8)
+
+#define GREG_BAR_PREFETCH (0x00000001 << 3)
+#define GREG_MSI_MM_CAP1 (0x00000000 << 0) // FIXME !
+#define GREG_MSI_MM_CAP2 (0x00000001 << 0)
+#define GREG_MSI_MM_CAP4 (0x00000002 << 0)
+#define GREG_MSI_MM_CAP8 (0x00000003 << 0)
+#define GREG_MSI_MM_CAP16 (0x00000004 << 0)
+#define GREG_MSI_MM_CAP32 (0x00000005 << 0)
+
+#define GREG_PMCSR_DATA_1 0x008
+#define GREG_PMCSR_DATA_2 0x00c
+#define GREG_VI_CTRL 0x010
+#define GREG_FGPI_CTRL 0x014
+
+#define GREG_RSTU_CTRL 0x018
+#define GREG_BOOT_READY (0x00000001 << 13)
+#define GREG_RESET_REQ (0x00000001 << 12)
+#define GREG_IP_RST_RELEASE (0x00000001 << 11)
+#define GREG_ADAPTER_RST_RELEASE (0x00000001 << 10)
+#define GREG_PCIE_CORE_RST_RELEASE (0x00000001 << 9)
+#define GREG_BOOT_IP_RST_RELEASE (0x00000001 << 8)
+#define GREG_BOOT_RST_RELEASE (0x00000001 << 7)
+#define GREG_CGU_RST_RELEASE (0x00000001 << 6)
+#define GREG_IP_RST_ASSERT (0x00000001 << 5)
+#define GREG_ADAPTER_RST_ASSERT (0x00000001 << 4)
+#define GREG_RST_ASSERT (0x00000001 << 3)
+#define GREG_BOOT_IP_RST_ASSERT (0x00000001 << 2)
+#define GREG_BOOT_RST_ASSERT (0x00000001 << 1)
+#define GREG_CGU_RST_ASSERT (0x00000001 << 0)
+
+#define GREG_I2C_CTRL 0x01c
+#define GREG_I2C_SLAVE_ADDR (0x0000007f << 0)
+
+#define GREG_OVFLW_CTRL 0x020
+#define GREG_OVERFLOW_ENABLE (0x00001fff << 0)
+
+#define GREG_TAG_ACK_FLEN 0x024
+#define GREG_TAG_ACK_FLEN_1B (0x00000000 << 0)
+#define GREG_TAG_ACK_FLEN_2B (0x00000001 << 0)
+#define GREG_TAG_ACK_FLEN_4B (0x00000002 << 0)
+#define GREG_TAG_ACK_FLEN_8B (0x00000003 << 0)
+
+#define GREG_VIDEO_IN_CTRL 0x028
+
+#define GREG_SPARE_1 0x02c
+#define GREG_SPARE_2 0x030
+#define GREG_SPARE_3 0x034
+#define GREG_SPARE_4 0x038
+#define GREG_SPARE_5 0x03c
+#define GREG_SPARE_6 0x040
+#define GREG_SPARE_7 0x044
+#define GREG_SPARE_8 0x048
+#define GREG_SPARE_9 0x04c
+#define GREG_SPARE_10 0x050
+#define GREG_SPARE_11 0x054
+#define GREG_SPARE_12 0x058
+#define GREG_SPARE_13 0x05c
+#define GREG_SPARE_14 0x060
+#define GREG_SPARE_15 0x064
+
+#define GREG_FAIL_DISABLE 0x068
+#define GREG_BOOT_FAIL_DISABLE (0x00000001 << 0)
+
+#define GREG_SW_RST 0xff0
+#define GREG_SW_RESET (0x00000001 << 0)
+
+
+#endif /* __SAA716x_GREG_REG_H */
diff --git a/drivers/media/common/saa716x/saa716x_hybrid.c b/drivers/media/common/saa716x/saa716x_hybrid.c
new file mode 100644
index 0000000..27e5e71
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_hybrid.c
@@ -0,0 +1,726 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/mutex.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/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include <linux/i2c.h>
+
+#include "saa716x_mod.h"
+
+#include "saa716x_gpio_reg.h"
+#include "saa716x_greg_reg.h"
+#include "saa716x_msi_reg.h"
+
+#include "saa716x_adap.h"
+#include "saa716x_i2c.h"
+#include "saa716x_msi.h"
+#include "saa716x_hybrid.h"
+#include "saa716x_gpio.h"
+#include "saa716x_rom.h"
+#include "saa716x_spi.h"
+#include "saa716x_priv.h"
+
+#include "zl10353.h"
+#include "mb86a16.h"
+#include "tda1004x.h"
+#include "tda827x.h"
+
+unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+
+unsigned int int_type;
+module_param(int_type, int, 0644);
+MODULE_PARM_DESC(int_type, "force Interrupt Handler type: 0=INT-A, 1=MSI, 2=MSI-X. default INT-A mode");
+
+#define DRIVER_NAME "SAA716x Hybrid"
+
+static int saa716x_hybrid_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+ struct saa716x_dev *saa716x;
+ int err = 0;
+
+ saa716x = kzalloc(sizeof (struct saa716x_dev), GFP_KERNEL);
+ if (saa716x == NULL) {
+ printk(KERN_ERR "saa716x_hybrid_pci_probe ERROR: out of memory\n");
+ err = -ENOMEM;
+ goto fail0;
+ }
+
+ saa716x->verbose = verbose;
+ saa716x->int_type = int_type;
+ saa716x->pdev = pdev;
+ saa716x->config = (struct saa716x_config *) pci_id->driver_data;
+
+ err = saa716x_pci_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x PCI Initialization failed");
+ goto fail1;
+ }
+
+ err = saa716x_cgu_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x CGU Init failed");
+ goto fail1;
+ }
+
+ err = saa716x_core_boot(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x Core Boot failed");
+ goto fail2;
+ }
+ dprintk(SAA716x_DEBUG, 1, "SAA716x Core Boot Success");
+
+ err = saa716x_msi_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x MSI Init failed");
+ goto fail2;
+ }
+
+ err = saa716x_jetpack_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x Jetpack core Initialization failed");
+ goto fail1;
+ }
+
+ err = saa716x_i2c_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x I2C Initialization failed");
+ goto fail3;
+ }
+
+ saa716x_gpio_init(saa716x);
+
+ err = saa716x_dump_eeprom(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x EEPROM dump failed");
+ }
+
+ err = saa716x_eeprom_data(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x EEPROM dump failed");
+ }
+
+ /* enable decoders on 7162 */
+ if (pdev->device == SAA7162) {
+ saa716x_gpio_set_output(saa716x, 24);
+ saa716x_gpio_set_output(saa716x, 25);
+
+ saa716x_gpio_write(saa716x, 24, 0);
+ saa716x_gpio_write(saa716x, 25, 0);
+
+ msleep(10);
+
+ saa716x_gpio_write(saa716x, 24, 1);
+ saa716x_gpio_write(saa716x, 25, 1);
+ }
+
+ /* set default port mapping */
+ SAA716x_EPWR(GREG, GREG_VI_CTRL, 0x2C688F44);
+ /* enable FGPI3 and FGPI0 for TS input from Port 3 and 6 */
+ SAA716x_EPWR(GREG, GREG_FGPI_CTRL, 0x894);
+
+ err = saa716x_dvb_init(saa716x);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x DVB initialization failed");
+ goto fail4;
+ }
+
+ return 0;
+
+fail4:
+ saa716x_dvb_exit(saa716x);
+fail3:
+ saa716x_i2c_exit(saa716x);
+fail2:
+ saa716x_pci_exit(saa716x);
+fail1:
+ kfree(saa716x);
+fail0:
+ return err;
+}
+
+static void saa716x_hybrid_pci_remove(struct pci_dev *pdev)
+{
+ struct saa716x_dev *saa716x = pci_get_drvdata(pdev);
+
+ saa716x_dvb_exit(saa716x);
+ saa716x_i2c_exit(saa716x);
+ saa716x_pci_exit(saa716x);
+ kfree(saa716x);
+}
+
+static irqreturn_t saa716x_hybrid_pci_irq(int irq, void *dev_id)
+{
+ struct saa716x_dev *saa716x = (struct saa716x_dev *) dev_id;
+
+ u32 stat_h, stat_l, mask_h, mask_l;
+
+ if (unlikely(saa716x == NULL)) {
+ printk("%s: saa716x=NULL", __func__);
+ return IRQ_NONE;
+ }
+
+ stat_l = SAA716x_EPRD(MSI, MSI_INT_STATUS_L);
+ stat_h = SAA716x_EPRD(MSI, MSI_INT_STATUS_H);
+ mask_l = SAA716x_EPRD(MSI, MSI_INT_ENA_L);
+ mask_h = SAA716x_EPRD(MSI, MSI_INT_ENA_H);
+
+ dprintk(SAA716x_DEBUG, 1, "MSI STAT L=<%02x> H=<%02x>, CTL L=<%02x> H=<%02x>",
+ stat_l, stat_h, mask_l, mask_h);
+
+ if (!((stat_l & mask_l) || (stat_h & mask_h)))
+ return IRQ_NONE;
+
+ if (stat_l)
+ SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_L, stat_l);
+
+ if (stat_h)
+ SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_H, stat_h);
+
+ saa716x_msi_event(saa716x, stat_l, stat_h);
+#if 0
+ dprintk(SAA716x_DEBUG, 1, "VI STAT 0=<%02x> 1=<%02x>, CTL 1=<%02x> 2=<%02x>",
+ SAA716x_EPRD(VI0, INT_STATUS),
+ SAA716x_EPRD(VI1, INT_STATUS),
+ SAA716x_EPRD(VI0, INT_ENABLE),
+ SAA716x_EPRD(VI1, INT_ENABLE));
+
+ dprintk(SAA716x_DEBUG, 1, "FGPI STAT 0=<%02x> 1=<%02x>, CTL 1=<%02x> 2=<%02x>",
+ SAA716x_EPRD(FGPI0, INT_STATUS),
+ SAA716x_EPRD(FGPI1, INT_STATUS),
+ SAA716x_EPRD(FGPI0, INT_ENABLE),
+ SAA716x_EPRD(FGPI0, INT_ENABLE));
+
+ dprintk(SAA716x_DEBUG, 1, "FGPI STAT 2=<%02x> 3=<%02x>, CTL 2=<%02x> 3=<%02x>",
+ SAA716x_EPRD(FGPI2, INT_STATUS),
+ SAA716x_EPRD(FGPI3, INT_STATUS),
+ SAA716x_EPRD(FGPI2, INT_ENABLE),
+ SAA716x_EPRD(FGPI3, INT_ENABLE));
+
+ dprintk(SAA716x_DEBUG, 1, "AI STAT 0=<%02x> 1=<%02x>, CTL 0=<%02x> 1=<%02x>",
+ SAA716x_EPRD(AI0, AI_STATUS),
+ SAA716x_EPRD(AI1, AI_STATUS),
+ SAA716x_EPRD(AI0, AI_CTL),
+ SAA716x_EPRD(AI1, AI_CTL));
+
+ dprintk(SAA716x_DEBUG, 1, "I2C STAT 0=<%02x> 1=<%02x>, CTL 0=<%02x> 1=<%02x>",
+ SAA716x_EPRD(I2C_A, INT_STATUS),
+ SAA716x_EPRD(I2C_B, INT_STATUS),
+ SAA716x_EPRD(I2C_A, INT_ENABLE),
+ SAA716x_EPRD(I2C_B, INT_ENABLE));
+
+ dprintk(SAA716x_DEBUG, 1, "DCS STAT=<%02x>, CTL=<%02x>",
+ SAA716x_EPRD(DCS, DCSC_INT_STATUS),
+ SAA716x_EPRD(DCS, DCSC_INT_ENABLE));
+#endif
+
+ if (stat_l) {
+ if (stat_l & MSI_INT_TAGACK_FGPI_0) {
+ tasklet_schedule(&saa716x->fgpi[0].tasklet);
+ }
+ if (stat_l & MSI_INT_TAGACK_FGPI_1) {
+ tasklet_schedule(&saa716x->fgpi[1].tasklet);
+ }
+ if (stat_l & MSI_INT_TAGACK_FGPI_2) {
+ tasklet_schedule(&saa716x->fgpi[2].tasklet);
+ }
+ if (stat_l & MSI_INT_TAGACK_FGPI_3) {
+ tasklet_schedule(&saa716x->fgpi[3].tasklet);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void demux_worker(unsigned long data)
+{
+ struct saa716x_fgpi_stream_port *fgpi_entry = (struct saa716x_fgpi_stream_port *)data;
+ struct saa716x_dev *saa716x = fgpi_entry->saa716x;
+ struct dvb_demux *demux;
+ u32 fgpi_index;
+ u32 i;
+ u32 write_index;
+
+ fgpi_index = fgpi_entry->dma_channel - 6;
+ demux = NULL;
+ for (i = 0; i < saa716x->config->adapters; i++) {
+ if (saa716x->config->adap_config[i].ts_port == fgpi_index) {
+ demux = &saa716x->saa716x_adap[i].demux;
+ break;
+ }
+ }
+ if (demux == NULL) {
+ printk(KERN_ERR "%s: unexpected channel %u\n",
+ __func__, fgpi_entry->dma_channel);
+ return;
+ }
+
+ write_index = saa716x_fgpi_get_write_index(saa716x, fgpi_index);
+ if (write_index < 0)
+ return;
+
+ dprintk(SAA716x_DEBUG, 1, "dma buffer = %d", write_index);
+
+ if (write_index == fgpi_entry->read_index) {
+ printk(KERN_DEBUG "%s: called but nothing to do\n", __func__);
+ return;
+ }
+
+ do {
+ u8 *data = (u8 *)fgpi_entry->dma_buf[fgpi_entry->read_index].mem_virt;
+
+ pci_dma_sync_sg_for_cpu(saa716x->pdev,
+ fgpi_entry->dma_buf[fgpi_entry->read_index].sg_list,
+ fgpi_entry->dma_buf[fgpi_entry->read_index].list_len,
+ PCI_DMA_FROMDEVICE);
+
+ dvb_dmx_swfilter(demux, data, 348 * 188);
+
+ fgpi_entry->read_index = (fgpi_entry->read_index + 1) & 7;
+ } while (write_index != fgpi_entry->read_index);
+}
+
+/*
+ * Twinhan/Azurewave VP-6090
+ * DVB-S Frontend: 2x MB86A16
+ * DVB-T Frontend: 2x TDA10046 + TDA8275
+ */
+#define SAA716x_MODEL_TWINHAN_VP6090 "Twinhan/Azurewave VP-6090"
+#define SAA716x_DEV_TWINHAN_VP6090 "2xDVB-S + 2xDVB-T + 2xAnalog"
+
+static int tda1004x_vp6090_request_firmware(struct dvb_frontend *fe,
+ const struct firmware **fw,
+ char *name)
+{
+ struct saa716x_adapter *adapter = fe->dvb->priv;
+
+ return request_firmware(fw, name, &adapter->saa716x->pdev->dev);
+}
+
+static struct tda1004x_config tda1004x_vp6090_config = {
+ .demod_address = 0x8,
+ .invert = 0,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .request_firmware = tda1004x_vp6090_request_firmware,
+};
+
+static int vp6090_dvbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct saa716x_dev *saa716x = fe->dvb->priv;
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ dprintk(SAA716x_ERROR, 1, "Polarization=[13V]");
+ break;
+ case SEC_VOLTAGE_18:
+ dprintk(SAA716x_ERROR, 1, "Polarization=[18V]");
+ break;
+ case SEC_VOLTAGE_OFF:
+ dprintk(SAA716x_ERROR, 1, "Frontend (dummy) POWERDOWN");
+ break;
+ default:
+ dprintk(SAA716x_ERROR, 1, "Invalid = (%d)", (u32 ) voltage);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+struct mb86a16_config vp6090_mb86a16_config = {
+ .demod_address = 0x08,
+ .set_voltage = vp6090_dvbs_set_voltage,
+};
+
+static int saa716x_vp6090_frontend_attach(struct saa716x_adapter *adapter, int count)
+{
+ struct saa716x_dev *saa716x = adapter->saa716x;
+ struct saa716x_i2c *i2c = &saa716x->i2c[count];
+
+ dprintk(SAA716x_ERROR, 1, "Adapter (%d) SAA716x frontend Init", count);
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device);
+
+ dprintk(SAA716x_ERROR, 1, "Adapter (%d) Power ON", count);
+
+ saa716x_gpio_set_output(saa716x, 11);
+ saa716x_gpio_set_output(saa716x, 10);
+ saa716x_gpio_write(saa716x, 11, 1);
+ saa716x_gpio_write(saa716x, 10, 1);
+ msleep(100);
+#if 0
+ dprintk(SAA716x_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)");
+ adapter->fe = mb86a16_attach(&vp6090_mb86a16_config, &i2c->i2c_adapter);
+ if (adapter->fe) {
+ dprintk(SAA716x_ERROR, 1, "found MB86A16 DVB-S/DSS frontend @0x%02x",
+ vp6090_mb86a16_config.demod_address);
+
+ } else {
+ goto exit;
+ }
+#endif
+ adapter->fe = tda10046_attach(&tda1004x_vp6090_config, &i2c->i2c_adapter);
+ if (adapter->fe == NULL) {
+ dprintk(SAA716x_ERROR, 1, "Frontend attach failed");
+ return -ENODEV;
+ } else {
+ dprintk(SAA716x_ERROR, 1, "Done!");
+ return 0;
+ }
+
+ return 0;
+}
+
+static struct saa716x_config saa716x_vp6090_config = {
+ .model_name = SAA716x_MODEL_TWINHAN_VP6090,
+ .dev_type = SAA716x_DEV_TWINHAN_VP6090,
+ .boot_mode = SAA716x_EXT_BOOT,
+ .adapters = 1,
+ .frontend_attach = saa716x_vp6090_frontend_attach,
+ .irq_handler = saa716x_hybrid_pci_irq,
+ .i2c_rate = SAA716x_I2C_RATE_100,
+};
+
+/*
+ * NXP Reference design (Atlantis)
+ * 2x DVB-T Frontend: 2x TDA10046
+ * Analog Decoder: 2x Internal
+ */
+#define SAA716x_MODEL_NXP_ATLANTIS "Atlantis reference board"
+#define SAA716x_DEV_NXP_ATLANTIS "2x DVB-T + 2x Analog"
+
+static int tda1004x_atlantis_request_firmware(struct dvb_frontend *fe,
+ const struct firmware **fw,
+ char *name)
+{
+ struct saa716x_adapter *adapter = fe->dvb->priv;
+
+ return request_firmware(fw, name, &adapter->saa716x->pdev->dev);
+}
+
+static struct tda1004x_config tda1004x_atlantis_config = {
+ .demod_address = 0x8,
+ .invert = 0,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .if_freq = TDA10046_FREQ_045,
+ .request_firmware = tda1004x_atlantis_request_firmware,
+ .tuner_address = 0x60,
+};
+
+static struct tda827x_config tda827x_atlantis_config = {
+ .init = NULL,
+ .sleep = NULL,
+ .config = 0,
+ .switch_addr = 0,
+ .agcf = NULL,
+};
+
+static int saa716x_atlantis_frontend_attach(struct saa716x_adapter *adapter,
+ int count)
+{
+ struct saa716x_dev *saa716x = adapter->saa716x;
+ struct saa716x_i2c *i2c;
+ u8 i2c_buf[3] = { 0x05, 0x23, 0x01 }; /* activate the silent I2C bus */
+ struct i2c_msg msg = {
+ .addr = 0x42 >> 1,
+ .flags = 0,
+ .buf = i2c_buf,
+ .len = sizeof(i2c_buf)
+ };
+
+ if (count < saa716x->config->adapters) {
+ u32 reset_gpio;
+
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init",
+ count);
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count,
+ saa716x->pdev->subsystem_device);
+
+ if (count == 0) {
+ reset_gpio = 14;
+ i2c = &saa716x->i2c[SAA716x_I2C_BUS_A];
+ } else {
+ reset_gpio = 15;
+ i2c = &saa716x->i2c[SAA716x_I2C_BUS_B];
+ }
+
+ /* activate the silent I2C bus */
+ i2c_transfer(&i2c->i2c_adapter, &msg, 1);
+
+ saa716x_gpio_set_output(saa716x, reset_gpio);
+
+ /* Reset the demodulator */
+ saa716x_gpio_write(saa716x, reset_gpio, 1);
+ msleep(10);
+ saa716x_gpio_write(saa716x, reset_gpio, 0);
+ msleep(10);
+ saa716x_gpio_write(saa716x, reset_gpio, 1);
+ msleep(10);
+
+ adapter->fe = tda10046_attach(&tda1004x_atlantis_config,
+ &i2c->i2c_adapter);
+ if (adapter->fe == NULL)
+ goto exit;
+
+ dprintk(SAA716x_ERROR, 1,
+ "found TDA10046 DVB-T frontend @0x%02x",
+ tda1004x_atlantis_config.demod_address);
+
+ if (dvb_attach(tda827x_attach, adapter->fe,
+ tda1004x_atlantis_config.tuner_address,
+ &i2c->i2c_adapter, &tda827x_atlantis_config)) {
+ dprintk(SAA716x_ERROR, 1, "found TDA8275 tuner @0x%02x",
+ tda1004x_atlantis_config.tuner_address);
+ } else {
+ goto exit;
+ }
+
+ dprintk(SAA716x_ERROR, 1, "Done!");
+ return 0;
+ }
+
+exit:
+ dprintk(SAA716x_ERROR, 1, "Frontend attach failed");
+ return -ENODEV;
+}
+
+static struct saa716x_config saa716x_atlantis_config = {
+ .model_name = SAA716x_MODEL_NXP_ATLANTIS,
+ .dev_type = SAA716x_DEV_NXP_ATLANTIS,
+ .boot_mode = SAA716x_EXT_BOOT,
+ .adapters = 2,
+ .frontend_attach = saa716x_atlantis_frontend_attach,
+ .irq_handler = saa716x_hybrid_pci_irq,
+ .i2c_rate = SAA716x_I2C_RATE_100,
+ .adap_config = {
+ {
+ /* Adapter 0 */
+ .ts_port = 3, /* using FGPI 3 */
+ .worker = demux_worker
+ },
+ {
+ /* Adapter 1 */
+ .ts_port = 0, /* using FGPI 0 */
+ .worker = demux_worker
+ }
+ }
+};
+
+/*
+ * NXP Reference design (NEMO)
+ * DVB-T Frontend: 1x TDA10046 + TDA8275
+ * Analog Decoder: External SAA7136
+ */
+#define SAA716x_MODEL_NXP_NEMO "NEMO reference board"
+#define SAA716x_DEV_NXP_NEMO "DVB-T + Analog"
+
+static int tda1004x_nemo_request_firmware(struct dvb_frontend *fe,
+ const struct firmware **fw,
+ char *name)
+{
+ struct saa716x_adapter *adapter = fe->dvb->priv;
+
+ return request_firmware(fw, name, &adapter->saa716x->pdev->dev);
+}
+
+static struct tda1004x_config tda1004x_nemo_config = {
+ .demod_address = 0x8,
+ .invert = 0,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .if_freq = TDA10046_FREQ_045,
+ .request_firmware = tda1004x_nemo_request_firmware,
+ .tuner_address = 0x60,
+};
+
+static struct tda827x_config tda827x_nemo_config = {
+ .init = NULL,
+ .sleep = NULL,
+ .config = 0,
+ .switch_addr = 0,
+ .agcf = NULL,
+};
+
+static int saa716x_nemo_frontend_attach(struct saa716x_adapter *adapter, int count)
+{
+ struct saa716x_dev *saa716x = adapter->saa716x;
+ struct saa716x_i2c *demod_i2c = &saa716x->i2c[SAA716x_I2C_BUS_B];
+ struct saa716x_i2c *tuner_i2c = &saa716x->i2c[SAA716x_I2C_BUS_A];
+
+
+ if (count == 0) {
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", count);
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device);
+ dprintk(SAA716x_ERROR, 1, "Adapter (%d) Power ON", count);
+
+ /* GPIO 26 controls a +15dB gain */
+ saa716x_gpio_set_output(saa716x, 26);
+ saa716x_gpio_write(saa716x, 26, 0);
+
+ saa716x_gpio_set_output(saa716x, 14);
+
+ /* Reset the demodulator */
+ saa716x_gpio_write(saa716x, 14, 1);
+ msleep(10);
+ saa716x_gpio_write(saa716x, 14, 0);
+ msleep(10);
+ saa716x_gpio_write(saa716x, 14, 1);
+ msleep(10);
+
+ adapter->fe = tda10046_attach(&tda1004x_nemo_config,
+ &demod_i2c->i2c_adapter);
+ if (adapter->fe) {
+ dprintk(SAA716x_ERROR, 1, "found TDA10046 DVB-T frontend @0x%02x",
+ tda1004x_nemo_config.demod_address);
+
+ } else {
+ goto exit;
+ }
+ if (dvb_attach(tda827x_attach, adapter->fe,
+ tda1004x_nemo_config.tuner_address,
+ &tuner_i2c->i2c_adapter, &tda827x_nemo_config)) {
+ dprintk(SAA716x_ERROR, 1, "found TDA8275 tuner @0x%02x",
+ tda1004x_nemo_config.tuner_address);
+ } else {
+ goto exit;
+ }
+ dprintk(SAA716x_ERROR, 1, "Done!");
+ }
+
+ return 0;
+exit:
+ dprintk(SAA716x_ERROR, 1, "Frontend attach failed");
+ return -ENODEV;
+}
+
+static struct saa716x_config saa716x_nemo_config = {
+ .model_name = SAA716x_MODEL_NXP_NEMO,
+ .dev_type = SAA716x_DEV_NXP_NEMO,
+ .boot_mode = SAA716x_EXT_BOOT,
+ .adapters = 1,
+ .frontend_attach = saa716x_nemo_frontend_attach,
+ .irq_handler = saa716x_hybrid_pci_irq,
+ .i2c_rate = SAA716x_I2C_RATE_100,
+
+ .adap_config = {
+ {
+ /* Adapter 0 */
+ .ts_port = 3, /* using FGPI 3 */
+ .worker = demux_worker
+ }
+ }
+};
+
+
+#define SAA716x_MODEL_AVERMEDIA_HC82 "Avermedia HC82 Express-54"
+#define SAA716x_DEV_AVERMEDIA_HC82 "DVB-T + Analog"
+
+#if 0
+static struct zl10353_config saa716x_averhc82_zl10353_config = {
+ .demod_address = 0x1f,
+ .adc_clock = 450560,
+ .if2 = 361667,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+};
+#endif
+
+static int saa716x_averhc82_frontend_attach(struct saa716x_adapter *adapter, int count)
+{
+ struct saa716x_dev *saa716x = adapter->saa716x;
+
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", count);
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device);
+
+// adapter->fe = zl10353_attach(&saa716x_averhc82_zl10353_config, &i2c->i2c_adapter);
+
+
+ return 0;
+}
+
+static struct saa716x_config saa716x_averhc82_config = {
+ .model_name = SAA716x_MODEL_AVERMEDIA_HC82,
+ .dev_type = SAA716x_DEV_AVERMEDIA_HC82,
+ .boot_mode = SAA716x_EXT_BOOT,
+ .adapters = 1,
+ .frontend_attach = saa716x_averhc82_frontend_attach,
+ .irq_handler = saa716x_hybrid_pci_irq,
+ .i2c_rate = SAA716x_I2C_RATE_100,
+};
+
+#define SAA716x_MODEL_AVERMEDIA_H788 "Avermedia H788"
+#define SAA716x_DEV_AVERMEDIA_H788 "DVB-T + Analaog"
+
+static int saa716x_averh88_frontend_attach(struct saa716x_adapter *adapter, int count)
+{
+ struct saa716x_dev *saa716x = adapter->saa716x;
+
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", count);
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device);
+
+ return -ENODEV;
+}
+
+static struct saa716x_config saa716x_averh788_config = {
+ .model_name = SAA716x_MODEL_AVERMEDIA_H788,
+ .dev_type = SAA716x_DEV_AVERMEDIA_H788,
+ .boot_mode = SAA716x_EXT_BOOT,
+ .adapters = 1,
+ .frontend_attach = saa716x_averh88_frontend_attach,
+ .irq_handler = saa716x_hybrid_pci_irq,
+ .i2c_rate = SAA716x_I2C_RATE_100,
+};
+
+static struct pci_device_id saa716x_hybrid_pci_table[] = {
+
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, TWINHAN_VP_6090, SAA7162, &saa716x_vp6090_config),
+ MAKE_ENTRY(AVERMEDIA, AVERMEDIA_HC82, SAA7160, &saa716x_averhc82_config),
+ MAKE_ENTRY(AVERMEDIA, AVERMEDIA_H788, SAA7160, &saa716x_averh788_config),
+ MAKE_ENTRY(KWORLD, KWORLD_DVB_T_PE310, SAA7162, &saa716x_atlantis_config),
+ MAKE_ENTRY(NXP_REFERENCE_BOARD, PCI_ANY_ID, SAA7162, &saa716x_atlantis_config),
+ MAKE_ENTRY(NXP_REFERENCE_BOARD, PCI_ANY_ID, SAA7160, &saa716x_nemo_config),
+ { }
+};
+MODULE_DEVICE_TABLE(pci, saa716x_hybrid_pci_table);
+
+static struct pci_driver saa716x_hybrid_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = saa716x_hybrid_pci_table,
+ .probe = saa716x_hybrid_pci_probe,
+ .remove = saa716x_hybrid_pci_remove,
+};
+
+static int saa716x_hybrid_init(void)
+{
+ return pci_register_driver(&saa716x_hybrid_pci_driver);
+}
+
+static void saa716x_hybrid_exit(void)
+{
+ return pci_unregister_driver(&saa716x_hybrid_pci_driver);
+}
+
+module_init(saa716x_hybrid_init);
+module_exit(saa716x_hybrid_exit);
+
+MODULE_DESCRIPTION("SAA716x Hybrid driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/saa716x/saa716x_hybrid.h b/drivers/media/common/saa716x/saa716x_hybrid.h
new file mode 100644
index 0000000..df34a59
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_hybrid.h
@@ -0,0 +1,13 @@
+#ifndef __SAA716x_HYBRID_H
+#define __SAA716x_HYBRID_H
+
+#define TWINHAN_TECHNOLOGIES 0x1822
+#define AVERMEDIA 0x1461
+#define KWORLD 0x17DE
+
+#define TWINHAN_VP_6090 0x0027
+#define AVERMEDIA_HC82 0x2355
+#define AVERMEDIA_H788 0x1455
+#define KWORLD_DVB_T_PE310 0x7521
+
+#endif /* __SAA716x_HYBRID_H */
diff --git a/drivers/media/common/saa716x/saa716x_i2c.c b/drivers/media/common/saa716x/saa716x_i2c.c
new file mode 100644
index 0000000..91a091d
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_i2c.c
@@ -0,0 +1,734 @@
+#include <linux/delay.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include <linux/i2c.h>
+
+#include "saa716x_mod.h"
+
+#include "saa716x_i2c_reg.h"
+#include "saa716x_msi_reg.h"
+#include "saa716x_cgu_reg.h"
+
+#include "saa716x_i2c.h"
+#include "saa716x_msi.h"
+#include "saa716x_spi.h"
+#include "saa716x_priv.h"
+
+#define SAA716x_I2C_TXFAIL (I2C_ERROR_IBE | \
+ I2C_ACK_INTER_MTNA | \
+ I2C_FAILURE_INTER_MAF)
+
+#define SAA716x_I2C_TXBUSY (I2C_TRANSMIT | \
+ I2C_TRANSMIT_PROG)
+
+#define SAA716x_I2C_RXBUSY (I2C_RECEIVE | \
+ I2C_RECEIVE_CLEAR)
+
+static const char* state[] = {
+ "Idle",
+ "DoneStop",
+ "Busy",
+ "TOscl",
+ "TOarb",
+ "DoneWrite",
+ "DoneRead",
+ "DoneWriteTO",
+ "DoneReadTO",
+ "NoDevice",
+ "NoACK",
+ "BUSErr",
+ "ArbLost",
+ "SEQErr",
+ "STErr"
+};
+
+int saa716x_i2c_irqevent(struct saa716x_dev *saa716x, u8 bus)
+{
+ u32 stat, mask;
+ u32 *I2C_DEV;
+
+ BUG_ON(saa716x == NULL);
+ I2C_DEV = saa716x->I2C_DEV;
+
+ stat = SAA716x_EPRD(I2C_DEV[bus], INT_STATUS);
+ mask = SAA716x_EPRD(I2C_DEV[bus], INT_ENABLE);
+ saa716x->i2c[bus].i2c_stat = stat;
+ dprintk(SAA716x_DEBUG, 0, "Bus(%d) I2C event: Status=<%s> --> Stat=<%02x> Mask=<%02x>",
+ bus, state[stat], stat, mask);
+
+ if (!(stat & mask))
+ return -1;
+
+ SAA716x_EPWR(I2C_DEV[bus], INT_CLR_STATUS, stat);
+
+ if (stat & I2C_INTERRUPT_STFNF)
+ dprintk(SAA716x_DEBUG, 0, "<STFNF> ");
+
+ if (stat & I2C_INTERRUPT_MTFNF) {
+ dprintk(SAA716x_DEBUG, 0, "<MTFNF> ");
+ }
+
+ if (stat & I2C_INTERRUPT_RFDA)
+ dprintk(SAA716x_DEBUG, 0, "<RFDA> ");
+
+ if (stat & I2C_INTERRUPTE_RFF)
+ dprintk(SAA716x_DEBUG, 0, "<RFF> ");
+
+ if (stat & I2C_SLAVE_INTERRUPT_STDR)
+ dprintk(SAA716x_DEBUG, 0, "<STDR> ");
+
+ if (stat & I2C_MASTER_INTERRUPT_MTDR) {
+ dprintk(SAA716x_DEBUG, 0, "<MTDR> ");
+ }
+
+ if (stat & I2C_ERROR_IBE)
+ dprintk(SAA716x_DEBUG, 0, "<IBE> ");
+
+ if (stat & I2C_MODE_CHANGE_INTER_MSMC)
+ dprintk(SAA716x_DEBUG, 0, "<MSMC> ");
+
+ if (stat & I2C_SLAVE_RECEIVE_INTER_SRSD)
+ dprintk(SAA716x_DEBUG, 0, "<SRSD> ");
+
+ if (stat & I2C_SLAVE_TRANSMIT_INTER_STSD)
+ dprintk(SAA716x_DEBUG, 0, "<STSD> ");
+
+ if (stat & I2C_ACK_INTER_MTNA)
+ dprintk(SAA716x_DEBUG, 0, "<MTNA> ");
+
+ if (stat & I2C_FAILURE_INTER_MAF)
+ dprintk(SAA716x_DEBUG, 0, "<MAF> ");
+
+ if (stat & I2C_INTERRUPT_MTD)
+ dprintk(SAA716x_DEBUG, 0, "<MTD> ");
+
+ return 0;
+}
+
+static irqreturn_t saa716x_i2c_irq(int irq, void *dev_id)
+{
+ struct saa716x_dev *saa716x = (struct saa716x_dev *) dev_id;
+
+ if (unlikely(saa716x == NULL)) {
+ printk("%s: saa716x=NULL", __func__);
+ return IRQ_NONE;
+ }
+ dprintk(SAA716x_DEBUG, 1, "MSI STAT L=<%02x> H=<%02x>, CTL L=<%02x> H=<%02x>",
+ SAA716x_EPRD(MSI, MSI_INT_STATUS_L),
+ SAA716x_EPRD(MSI, MSI_INT_STATUS_H),
+ SAA716x_EPRD(MSI, MSI_INT_ENA_L),
+ SAA716x_EPRD(MSI, MSI_INT_ENA_H));
+
+ dprintk(SAA716x_DEBUG, 1, "I2C STAT 0=<%02x> 1=<%02x>, CTL 0=<%02x> 1=<%02x>",
+ SAA716x_EPRD(I2C_A, INT_STATUS),
+ SAA716x_EPRD(I2C_B, INT_STATUS),
+ SAA716x_EPRD(I2C_A, INT_CLR_STATUS),
+ SAA716x_EPRD(I2C_B, INT_CLR_STATUS));
+
+ return IRQ_HANDLED;
+}
+
+static void saa716x_term_xfer(struct saa716x_i2c *i2c, u32 I2C_DEV)
+{
+ struct saa716x_dev *saa716x = i2c->saa716x;
+
+ SAA716x_EPWR(I2C_DEV, I2C_CONTROL, 0xc0); /* Start: SCL/SDA High */
+ msleep(10);
+ SAA716x_EPWR(I2C_DEV, I2C_CONTROL, 0x80);
+ msleep(10);
+ SAA716x_EPWR(I2C_DEV, I2C_CONTROL, 0x00);
+ msleep(10);
+ SAA716x_EPWR(I2C_DEV, I2C_CONTROL, 0x80);
+ msleep(10);
+ SAA716x_EPWR(I2C_DEV, I2C_CONTROL, 0xc0);
+
+ return;
+}
+
+static void saa716x_i2c_hwdeinit(struct saa716x_i2c *i2c, u32 I2C_DEV)
+{
+ struct saa716x_dev *saa716x = i2c->saa716x;
+
+ /* Disable all interrupts and clear status */
+ SAA716x_EPWR(I2C_DEV, INT_CLR_ENABLE, 0x1fff);
+ SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff);
+}
+
+static int saa716x_i2c_hwinit(struct saa716x_i2c *i2c, u32 I2C_DEV)
+{
+ struct saa716x_dev *saa716x = i2c->saa716x;
+ struct i2c_adapter *adapter = &i2c->i2c_adapter;
+
+ int i, err = 0;
+ u32 reg;
+
+ reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS);
+ if (!(reg & 0xd)) {
+ dprintk(SAA716x_ERROR, 1, "Adapter (%02x) %s RESET failed, Exiting !",
+ I2C_DEV, adapter->name);
+ err = -EIO;
+ goto exit;
+ }
+
+ /* Flush queue */
+ SAA716x_EPWR(I2C_DEV, I2C_CONTROL, 0xcc);
+
+ /* Disable all interrupts and clear status */
+ SAA716x_EPWR(I2C_DEV, INT_CLR_ENABLE, 0x1fff);
+ SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff);
+
+ /* Reset I2C Core and generate a delay */
+ SAA716x_EPWR(I2C_DEV, I2C_CONTROL, 0xc1);
+
+ for (i = 0; i < 100; i++) {
+ reg = SAA716x_EPRD(I2C_DEV, I2C_CONTROL);
+ if (reg == 0xc0) {
+ dprintk(SAA716x_ERROR, 1, "Adapter (%02x) %s RESET",
+ I2C_DEV, adapter->name);
+ break;
+ }
+ msleep(1);
+
+ if (i == 99)
+ err = -EIO;
+ }
+
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "Adapter (%02x) %s RESET failed",
+ I2C_DEV, adapter->name);
+
+ saa716x_term_xfer(i2c, I2C_DEV);
+ err = -EIO;
+ goto exit;
+ }
+
+ /* I2C Rate Setup */
+ switch (i2c->i2c_rate) {
+ case SAA716x_I2C_RATE_400:
+
+ dprintk(SAA716x_DEBUG, 1, "Initializing Adapter %s @ 400k", adapter->name);
+ SAA716x_EPWR(I2C_DEV, I2C_CLOCK_DIVISOR_HIGH, 0x1a); /* 0.5 * 27MHz/400kHz */
+ SAA716x_EPWR(I2C_DEV, I2C_CLOCK_DIVISOR_LOW, 0x21); /* 0.5 * 27MHz/400kHz */
+ SAA716x_EPWR(I2C_DEV, I2C_SDA_HOLD, 0x19);
+ break;
+
+ case SAA716x_I2C_RATE_100:
+
+ dprintk(SAA716x_DEBUG, 1, "Initializing Adapter %s @ 100k", adapter->name);
+ SAA716x_EPWR(I2C_DEV, I2C_CLOCK_DIVISOR_HIGH, 0x68); /* 0.5 * 27MHz/100kHz */
+ SAA716x_EPWR(I2C_DEV, I2C_CLOCK_DIVISOR_LOW, 0x87); /* 0.5 * 27MHz/100kHz */
+ SAA716x_EPWR(I2C_DEV, I2C_SDA_HOLD, 0x60);
+ break;
+
+ default:
+
+ dprintk(SAA716x_ERROR, 1, "Adapter %s Unknown Rate (Rate=0x%02x)",
+ adapter->name,
+ i2c->i2c_rate);
+
+ break;
+ }
+
+ /* Disable all interrupts and clear status */
+ SAA716x_EPWR(I2C_DEV, INT_CLR_ENABLE, 0x1fff);
+ SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff);
+
+ if (i2c->i2c_mode >= SAA716x_I2C_MODE_IRQ) {
+ /* Enabled interrupts:
+ * Master Transaction Done,
+ * Master Transaction Data Request
+ * (0x81)
+ */
+ msleep(5);
+
+ SAA716x_EPWR(I2C_DEV, INT_SET_ENABLE,
+ I2C_SET_ENABLE_MTDR | I2C_SET_ENABLE_MTD);
+
+ /* Check interrupt enable status */
+ reg = SAA716x_EPRD(I2C_DEV, INT_ENABLE);
+ if (reg != 0x81) {
+
+ dprintk(SAA716x_ERROR, 1,
+ "Adapter (%d) %s Interrupt enable failed, Exiting !",
+ i,
+ adapter->name);
+
+ err = -EIO;
+ goto exit;
+ }
+ }
+
+ /* Check status */
+ reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS);
+ if (!(reg & 0xd)) {
+
+ dprintk(SAA716x_ERROR, 1,
+ "Adapter (%02x) %s has bad state, Exiting !",
+ I2C_DEV,
+ adapter->name);
+
+ err = -EIO;
+ goto exit;
+ }
+#if 0
+ saa716x_add_irqvector(saa716x,
+ i2c_vec[i].vector,
+ i2c_vec[i].edge,
+ i2c_vec[i].handler,
+ SAA716x_I2C_ADAPTER(i));
+#endif
+ reg = SAA716x_EPRD(CGU, CGU_SCR_3);
+ dprintk(SAA716x_DEBUG, 1, "Adapter (%02x) Autowake <%d> Active <%d>",
+ I2C_DEV,
+ (reg >> 1) & 0x01,
+ reg & 0x01);
+
+ return 0;
+exit:
+ return err;
+}
+
+static int saa716x_i2c_send(struct saa716x_i2c *i2c, u32 I2C_DEV, u32 data)
+{
+ struct saa716x_dev *saa716x = i2c->saa716x;
+ int i, err = 0;
+ u32 reg;
+
+ if (i2c->i2c_mode >= SAA716x_I2C_MODE_IRQ) {
+ /* Write to FIFO */
+ SAA716x_EPWR(I2C_DEV, TX_FIFO, data);
+ return 0;
+ }
+
+ /* Check FIFO status before TX */
+ reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS);
+ i2c->stat_tx_prior = reg;
+ if (reg & SAA716x_I2C_TXBUSY) {
+ for (i = 0; i < 100; i++) {
+ /* TODO! check for hotplug devices */
+ msleep(10);
+ reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS);
+
+ if (reg & SAA716x_I2C_TXBUSY) {
+ dprintk(SAA716x_ERROR, 1, "FIFO full or Blocked");
+
+ err = saa716x_i2c_hwinit(i2c, I2C_DEV);
+ if (err < 0) {
+ dprintk(SAA716x_ERROR, 1, "Error Reinit");
+ err = -EIO;
+ goto exit;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ /* Write to FIFO */
+ SAA716x_EPWR(I2C_DEV, TX_FIFO, data);
+
+ /* Check for data write */
+ for (i = 0; i < 1000; i++) {
+ /* TODO! check for hotplug devices */
+ reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS);
+ if (reg & I2C_TRANSMIT_CLEAR) {
+ break;
+ }
+ }
+ i2c->stat_tx_done = reg;
+
+ if (!(reg & I2C_TRANSMIT_CLEAR)) {
+ dprintk(SAA716x_ERROR, 1, "TXFIFO not empty after Timeout, tried %d loops!", i);
+ err = -EIO;
+ goto exit;
+ }
+
+ return err;
+
+exit:
+ dprintk(SAA716x_ERROR, 1, "I2C Send failed (Err=%d)", err);
+ return err;
+}
+
+static int saa716x_i2c_recv(struct saa716x_i2c *i2c, u32 I2C_DEV, u32 *data)
+{
+ struct saa716x_dev *saa716x = i2c->saa716x;
+ int i, err = 0;
+ u32 reg;
+
+ /* Check FIFO status before RX */
+ for (i = 0; i < 1000; i++) {
+ reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS);
+ if (!(reg & SAA716x_I2C_RXBUSY)) {
+ break;
+ }
+ }
+ if (reg & SAA716x_I2C_RXBUSY) {
+ dprintk(SAA716x_INFO, 1, "FIFO empty");
+ err = -EIO;
+ goto exit;
+ }
+
+ /* Read from FIFO */
+ *data = SAA716x_EPRD(I2C_DEV, RX_FIFO);
+
+ return 0;
+exit:
+ dprintk(SAA716x_ERROR, 1, "Error Reading data, err=%d", err);
+ return err;
+}
+
+static void saa716x_i2c_irq_start(struct saa716x_i2c *i2c, u32 I2C_DEV)
+{
+ struct saa716x_dev *saa716x = i2c->saa716x;
+
+ if (i2c->i2c_mode == SAA716x_I2C_MODE_POLLING)
+ return;
+
+ i2c->i2c_op = 1;
+ SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff);
+}
+
+static int saa716x_i2c_irq_wait(struct saa716x_i2c *i2c, u32 I2C_DEV)
+{
+ struct saa716x_dev *saa716x = i2c->saa716x;
+ unsigned long timeout;
+ int err = 0;
+
+ if (i2c->i2c_mode == SAA716x_I2C_MODE_POLLING)
+ return 0;
+
+ timeout = HZ/100 + 1; /* 10ms */
+ timeout = wait_event_interruptible_timeout(i2c->i2c_wq, i2c->i2c_op == 0, timeout);
+ if (timeout == -ERESTARTSYS || i2c->i2c_op) {
+ SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff);
+ if (timeout == -ERESTARTSYS) {
+ /* a signal arrived */
+ err = -ERESTARTSYS;
+ } else {
+ dprintk(SAA716x_ERROR, 1, "timed out waiting for end of xfer!");
+ err = -EIO;
+ }
+ }
+ return err;
+}
+
+static int saa716x_i2c_write_msg(struct saa716x_i2c *i2c, u32 I2C_DEV,
+ u16 addr, u8 *buf, u16 len, u8 add_stop)
+{
+ struct saa716x_dev *saa716x = i2c->saa716x;
+ u32 data;
+ int err;
+ int i;
+ int bytes;
+
+ saa716x_i2c_irq_start(i2c, I2C_DEV);
+
+ /* first write START with I2C address */
+ data = I2C_START_BIT | (addr << 1);
+ dprintk(SAA716x_DEBUG, 1, "length=%d Addr:0x%02x", len, data);
+ err = saa716x_i2c_send(i2c, I2C_DEV, data);
+ if (err < 0) {
+ dprintk(SAA716x_ERROR, 1, "Address write failed");
+ goto exit;
+ }
+
+ bytes = i2c->block_size - 1;
+
+ /* now write the data */
+ while (len > 0) {
+ if (bytes == i2c->block_size) {
+ /* this is not the first round, so restart irq */
+ saa716x_i2c_irq_start(i2c, I2C_DEV);
+ }
+
+ if (bytes > len)
+ bytes = len;
+
+ for (i = 0; i < bytes; i++) {
+ data = buf[i];
+ dprintk(SAA716x_DEBUG, 0, " <W %04x> 0x%02x\n", i, data);
+ if (add_stop && i == (len - 1))
+ data |= I2C_STOP_BIT;
+ err = saa716x_i2c_send(i2c, I2C_DEV, data);
+ if (err < 0) {
+ dprintk(SAA716x_ERROR, 1, "Data send failed");
+ goto exit;
+ }
+ }
+
+ err = saa716x_i2c_irq_wait(i2c, I2C_DEV);
+ if (err < 0) {
+ goto exit;
+ }
+
+ len -= bytes;
+ buf += bytes;
+ bytes = i2c->block_size;
+ }
+
+ return 0;
+
+exit:
+ dprintk(SAA716x_ERROR, 1, "Error writing data, err=%d", err);
+ return err;
+}
+
+static int saa716x_i2c_read_msg(struct saa716x_i2c *i2c, u32 I2C_DEV,
+ u16 addr, u8 *buf, u16 len, u8 add_stop)
+{
+ struct saa716x_dev *saa716x = i2c->saa716x;
+ u32 data;
+ int err;
+ int i;
+ int bytes;
+
+ saa716x_i2c_irq_start(i2c, I2C_DEV);
+
+ /* first write START with I2C address */
+ data = I2C_START_BIT | (addr << 1) | 1;
+ dprintk(SAA716x_DEBUG, 1, "length=%d Addr:0x%02x", len, data);
+ err = saa716x_i2c_send(i2c, I2C_DEV, data);
+ if (err < 0) {
+ dprintk(SAA716x_ERROR, 1, "Address write failed");
+ goto exit;
+ }
+
+ bytes = i2c->block_size - 1;
+
+ /* now read the data */
+ while (len > 0) {
+ if (bytes == i2c->block_size) {
+ /* this is not the first round, so restart irq */
+ saa716x_i2c_irq_start(i2c, I2C_DEV);
+ }
+
+ if (bytes > len)
+ bytes = len;
+
+ for (i = 0; i < bytes; i++) {
+ data = 0x00; /* dummy write for reading */
+ if (add_stop && i == (len - 1))
+ data |= I2C_STOP_BIT;
+ err = saa716x_i2c_send(i2c, I2C_DEV, data);
+ if (err < 0) {
+ dprintk(SAA716x_ERROR, 1, "Data send failed");
+ goto exit;
+ }
+ }
+
+ err = saa716x_i2c_irq_wait(i2c, I2C_DEV);
+ if (err < 0) {
+ goto exit;
+ }
+
+ for (i = 0; i < bytes; i++) {
+ err = saa716x_i2c_recv(i2c, I2C_DEV, &data);
+ if (err < 0) {
+ dprintk(SAA716x_ERROR, 1, "Data receive failed");
+ goto exit;
+ }
+ dprintk(SAA716x_DEBUG, 0, " <R %04x> 0x%02x\n\n", i, data);
+ buf[i] = data;
+ }
+
+ len -= bytes;
+ buf += bytes;
+ bytes = i2c->block_size;
+ }
+
+ return 0;
+
+exit:
+ dprintk(SAA716x_ERROR, 1, "Error reading data, err=%d", err);
+ return err;
+}
+
+static int saa716x_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+{
+ struct saa716x_i2c *i2c = i2c_get_adapdata(adapter);
+ struct saa716x_dev *saa716x = i2c->saa716x;
+
+ u32 DEV = SAA716x_I2C_BUS(i2c->i2c_dev);
+ int i, j, err = 0;
+ int t;
+
+ dprintk(SAA716x_DEBUG, 0, "\n");
+ dprintk(SAA716x_DEBUG, 1, "Bus(%02x) I2C transfer", DEV);
+ mutex_lock(&i2c->i2c_lock);
+
+ for (t = 0; t < 3; t++) {
+ for (i = 0; i < num; i++) {
+ if (msgs[i].flags & I2C_M_RD)
+ err = saa716x_i2c_read_msg(i2c, DEV,
+ msgs[i].addr, msgs[i].buf, msgs[i].len,
+ i == (num - 1));
+ else
+ err = saa716x_i2c_write_msg(i2c, DEV,
+ msgs[i].addr, msgs[i].buf, msgs[i].len,
+ i == (num - 1));
+ if (err < 0) {
+ err = -EIO;
+ goto retry;
+ }
+ }
+ break;
+retry:
+ dprintk(SAA716x_INFO, 1, "Error in Transfer, try %d", t);
+ for (i = 0; i < num; i++) {
+ dprintk(SAA716x_INFO, 1, "msg %d, addr = 0x%02x, len=%d, flags=0x%x",
+ i, msgs[i].addr, msgs[i].len, msgs[i].flags);
+ if (!(msgs[i].flags & I2C_M_RD)) {
+ for (j = 0; j < msgs[i].len; j++) {
+ dprintk(SAA716x_INFO, 1, " <W %04x> 0x%02x",
+ j, msgs[i].buf[j]);
+ }
+ }
+ }
+ err = saa716x_i2c_hwinit(i2c, DEV);
+ if (err < 0) {
+ dprintk(SAA716x_ERROR, 1, "Error Reinit");
+ err = -EIO;
+ goto bail_out;
+ }
+ }
+
+ mutex_unlock(&i2c->i2c_lock);
+ return num;
+
+bail_out:
+ dprintk(SAA716x_ERROR, 1, "ERROR: Bailing out <%d>", err);
+ mutex_unlock(&i2c->i2c_lock);
+ return err;
+}
+
+static u32 saa716x_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm saa716x_algo = {
+ .master_xfer = saa716x_i2c_xfer,
+ .functionality = saa716x_i2c_func,
+};
+
+struct saa716x_i2cvec {
+ u32 vector;
+ enum saa716x_edge edge;
+ irqreturn_t (*handler)(int irq, void *dev_id);
+};
+
+static const struct saa716x_i2cvec i2c_vec[] = {
+ {
+ .vector = I2CINT_0,
+ .edge = SAA716x_EDGE_RISING,
+ .handler = saa716x_i2c_irq
+ }, {
+ .vector = I2CINT_1,
+ .edge = SAA716x_EDGE_RISING,
+ .handler = saa716x_i2c_irq
+ }
+};
+
+int saa716x_i2c_init(struct saa716x_dev *saa716x)
+{
+ struct pci_dev *pdev = saa716x->pdev;
+ struct saa716x_i2c *i2c = saa716x->i2c;
+ struct i2c_adapter *adapter = NULL;
+
+ int i, err = 0;
+
+ dprintk(SAA716x_DEBUG, 1, "Initializing SAA%02x I2C Core",
+ saa716x->pdev->device);
+
+ for (i = 0; i < SAA716x_I2C_ADAPTERS; i++) {
+
+ mutex_init(&i2c->i2c_lock);
+
+ init_waitqueue_head(&i2c->i2c_wq);
+ i2c->i2c_op = 0;
+
+ i2c->i2c_dev = i;
+ i2c->i2c_rate = saa716x->config->i2c_rate;
+ i2c->i2c_mode = saa716x->config->i2c_mode;
+ adapter = &i2c->i2c_adapter;
+
+ if (i2c->i2c_mode == SAA716x_I2C_MODE_IRQ_BUFFERED)
+ i2c->block_size = 8;
+ else
+ i2c->block_size = 1;
+
+ if (adapter != NULL) {
+
+ i2c_set_adapdata(adapter, i2c);
+
+ strcpy(adapter->name, SAA716x_I2C_ADAPTER(i));
+
+ adapter->owner = THIS_MODULE;
+ adapter->algo = &saa716x_algo;
+ adapter->algo_data = NULL;
+ adapter->timeout = 500; /* FIXME ! */
+ adapter->retries = 3; /* FIXME ! */
+ adapter->dev.parent = &pdev->dev;
+
+ dprintk(SAA716x_DEBUG, 1, "Initializing adapter (%d) %s",
+ i,
+ adapter->name);
+
+ err = i2c_add_adapter(adapter);
+ if (err < 0) {
+ dprintk(SAA716x_ERROR, 1, "Adapter (%d) %s init failed", i, adapter->name);
+ goto exit;
+ }
+
+ i2c->saa716x = saa716x;
+ saa716x_i2c_hwinit(i2c, SAA716x_I2C_BUS(i));
+ }
+ i2c++;
+ }
+
+ if (saa716x->config->i2c_mode >= SAA716x_I2C_MODE_IRQ) {
+ SAA716x_EPWR(MSI, MSI_INT_ENA_SET_H, MSI_INT_I2CINT_0);
+ SAA716x_EPWR(MSI, MSI_INT_ENA_SET_H, MSI_INT_I2CINT_1);
+ }
+
+ dprintk(SAA716x_DEBUG, 1, "SAA%02x I2C Core succesfully initialized",
+ saa716x->pdev->device);
+
+ return 0;
+exit:
+ return err;
+}
+EXPORT_SYMBOL_GPL(saa716x_i2c_init);
+
+int saa716x_i2c_exit(struct saa716x_dev *saa716x)
+{
+ struct saa716x_i2c *i2c = saa716x->i2c;
+ struct i2c_adapter *adapter = NULL;
+ int i, err = 0;
+
+ dprintk(SAA716x_DEBUG, 1, "Removing SAA%02x I2C Core", saa716x->pdev->device);
+
+ for (i = 0; i < SAA716x_I2C_ADAPTERS; i++) {
+
+ adapter = &i2c->i2c_adapter;
+#if 0
+ saa716x_remove_irqvector(saa716x, i2c_vec[i].vector);
+#endif
+ saa716x_i2c_hwdeinit(i2c, SAA716x_I2C_BUS(i));
+ dprintk(SAA716x_DEBUG, 1, "Removing adapter (%d) %s", i, adapter->name);
+
+ i2c_del_adapter(adapter);
+ i2c++;
+ }
+ dprintk(SAA716x_DEBUG, 1, "SAA%02x I2C Core succesfully removed", saa716x->pdev->device);
+
+ return 0;
+
+exit:
+ return err;
+}
+EXPORT_SYMBOL_GPL(saa716x_i2c_exit);
diff --git a/drivers/media/common/saa716x/saa716x_i2c.h b/drivers/media/common/saa716x/saa716x_i2c.h
new file mode 100644
index 0000000..da767ac
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_i2c.h
@@ -0,0 +1,52 @@
+#ifndef __SAA716x_I2C_H
+#define __SAA716x_I2C_H
+
+#define SAA716x_I2C_ADAPTERS 2
+
+#define SAA716x_I2C_ADAPTER(__dev) (( \
+ (__dev == 1) ? \
+ "SAA716x I2C Core 1" : \
+ "SAA716x I2C Core 0"))
+
+#define SAA716x_I2C_BUS(__x) ((__x == 1) ? 0x0000c000 : 0x0000b000)
+
+#define SAA716x_I2C_BUS_A 0x01
+#define SAA716x_I2C_BUS_B 0x00
+
+struct saa716x_dev;
+
+enum saa716x_i2c_rate {
+ SAA716x_I2C_RATE_400 = 1,
+ SAA716x_I2C_RATE_100,
+};
+
+enum saa716x_i2c_mode {
+ SAA716x_I2C_MODE_POLLING = 0,
+ SAA716x_I2C_MODE_IRQ,
+ SAA716x_I2C_MODE_IRQ_BUFFERED
+};
+
+struct saa716x_i2c {
+ struct i2c_adapter i2c_adapter;
+ struct mutex i2c_lock;
+ struct saa716x_dev *saa716x;
+ u8 i2c_dev;
+
+ enum saa716x_i2c_rate i2c_rate; /* run time */
+ enum saa716x_i2c_mode i2c_mode;
+ u32 block_size; /* block size for buffered
+ mode, 1 otherwise */
+ u32 i2c_stat;
+
+ u32 stat_tx_prior;
+ u32 stat_tx_done;
+ wait_queue_head_t i2c_wq;
+ int i2c_op;
+};
+
+extern int saa716x_i2c_init(struct saa716x_dev *saa716x);
+extern int saa716x_i2c_exit(struct saa716x_dev *saa716x);
+extern void saa716x_i2cint_disable(struct saa716x_dev *saa716x);
+extern int saa716x_i2c_irqevent(struct saa716x_dev *saa716x, u8 bus);
+
+#endif /* __SAA716x_I2C_H */
diff --git a/drivers/media/common/saa716x/saa716x_i2c_reg.h b/drivers/media/common/saa716x/saa716x_i2c_reg.h
new file mode 100644
index 0000000..8fa992c
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_i2c_reg.h
@@ -0,0 +1,145 @@
+#ifndef __SAA716x_I2C_REG_H
+#define __SAA716x_I2C_REG_H
+
+/* -------------- I2C Registers -------------- */
+
+#define RX_FIFO 0x000
+#define I2C_RX_BYTE (0x000000ff << 0)
+
+#define TX_FIFO 0x000
+#define I2C_STOP_BIT (0x00000001 << 9)
+#define I2C_START_BIT (0x00000001 << 8)
+#define I2C_TX_BYTE (0x000000ff << 0)
+
+#define I2C_STATUS 0x008
+#define I2C_TRANSMIT (0x00000001 << 11)
+#define I2C_RECEIVE (0x00000001 << 10)
+#define I2C_TRANSMIT_S_PROG (0x00000001 << 9)
+#define I2C_TRANSMIT_S_CLEAR (0x00000001 << 8)
+#define I2C_TRANSMIT_PROG (0x00000001 << 7)
+#define I2C_TRANSMIT_CLEAR (0x00000001 << 6)
+#define I2C_RECEIVE_PROG (0x00000001 << 5)
+#define I2C_RECEIVE_CLEAR (0x00000001 << 4)
+#define I2C_SDA_LINE (0x00000001 << 3)
+#define I2C_SCL_LINE (0x00000001 << 2)
+#define I2C_START_STOP_FLAG (0x00000001 << 1)
+#define I2C_MODE_STATUS (0x00000001 << 0)
+
+#define I2C_CONTROL 0x00c
+#define I2C_SCL_CONTROL (0x00000001 << 7)
+#define I2C_SDA_CONTROL (0x00000001 << 6)
+#define I2C_RECEIVE_PROTECT (0x00000001 << 5)
+#define I2C_RECEIVE_PRO_READ (0x00000001 << 4)
+#define I2C_TRANS_SELF_CLEAR (0x00000001 << 3)
+#define I2C_TRANS_S_SELF_CLEAR (0x00000001 << 2)
+#define I2C_SLAVE_ADDR_10BIT (0x00000001 << 1)
+#define I2C_RESET (0x00000001 << 0)
+
+#define I2C_CLOCK_DIVISOR_HIGH 0x010
+#define I2C_CLOCK_HIGH (0x0000ffff << 0)
+
+#define I2C_CLOCK_DIVISOR_LOW 0x014
+#define I2C_CLOCK_LOW (0x0000ffff << 0)
+
+#define I2C_RX_LEVEL 0x01c
+#define I2C_RECEIVE_RANGE (0x0000007f << 0)
+
+#define I2C_TX_LEVEL 0x020
+#define I2C_TRANSMIT_RANGE (0x0000007f << 0)
+
+#define I2C_SDA_HOLD 0x028
+#define I2C_HOLD_TIME (0x0000007f << 0)
+
+#define MODULE_CONF 0xfd4
+#define INT_CLR_ENABLE 0xfd8
+#define I2C_CLR_ENABLE_STFNF (0x00000001 << 12)
+#define I2C_CLR_ENABLE_MTFNF (0x00000001 << 11)
+#define I2C_CLR_ENABLE_RFDA (0x00000001 << 10)
+#define I2C_CLR_ENABLE_RFF (0x00000001 << 9)
+#define I2C_CLR_ENABLE_STDR (0x00000001 << 8)
+#define I2C_CLR_ENABLE_MTDR (0x00000001 << 7)
+#define I2C_CLR_ENABLE_IBE (0x00000001 << 6)
+#define I2C_CLR_ENABLE_MSMC (0x00000001 << 5)
+#define I2C_CLR_ENABLE_SRSD (0x00000001 << 4)
+#define I2C_CLR_ENABLE_STSD (0x00000001 << 3)
+#define I2C_CLR_ENABLE_MTNA (0x00000001 << 2)
+#define I2C_CLR_ENABLE_MAF (0x00000001 << 1)
+#define I2C_CLR_ENABLE_MTD (0x00000001 << 0)
+
+#define INT_SET_ENABLE 0xfdc
+#define I2C_SET_ENABLE_STFNF (0x00000001 << 12)
+#define I2C_SET_ENABLE_MTFNF (0x00000001 << 11)
+#define I2C_SET_ENABLE_RFDA (0x00000001 << 10)
+#define I2C_SET_ENABLE_RFF (0x00000001 << 9)
+#define I2C_SET_ENABLE_STDR (0x00000001 << 8)
+#define I2C_SET_ENABLE_MTDR (0x00000001 << 7)
+#define I2C_SET_ENABLE_IBE (0x00000001 << 6)
+#define I2C_SET_ENABLE_MSMC (0x00000001 << 5)
+#define I2C_SET_ENABLE_SRSD (0x00000001 << 4)
+#define I2C_SET_ENABLE_STSD (0x00000001 << 3)
+#define I2C_SET_ENABLE_MTNA (0x00000001 << 2)
+#define I2C_SET_ENABLE_MAF (0x00000001 << 1)
+#define I2C_SET_ENABLE_MTD (0x00000001 << 0)
+
+#define INT_STATUS 0xfe0
+#define I2C_INTERRUPT_STFNF (0x00000001 << 12)
+#define I2C_INTERRUPT_MTFNF (0x00000001 << 11)
+#define I2C_INTERRUPT_RFDA (0x00000001 << 10)
+#define I2C_INTERRUPTE_RFF (0x00000001 << 9)
+#define I2C_SLAVE_INTERRUPT_STDR (0x00000001 << 8)
+#define I2C_MASTER_INTERRUPT_MTDR (0x00000001 << 7)
+#define I2C_ERROR_IBE (0x00000001 << 6)
+#define I2C_MODE_CHANGE_INTER_MSMC (0x00000001 << 5)
+#define I2C_SLAVE_RECEIVE_INTER_SRSD (0x00000001 << 4)
+#define I2C_SLAVE_TRANSMIT_INTER_STSD (0x00000001 << 3)
+#define I2C_ACK_INTER_MTNA (0x00000001 << 2)
+#define I2C_FAILURE_INTER_MAF (0x00000001 << 1)
+#define I2C_INTERRUPT_MTD (0x00000001 << 0)
+
+#define INT_ENABLE 0xfe4
+#define I2C_ENABLE_STFNF (0x00000001 << 12)
+#define I2C_ENABLE_MTFNF (0x00000001 << 11)
+#define I2C_ENABLE_RFDA (0x00000001 << 10)
+#define I2C_ENABLE_RFF (0x00000001 << 9)
+#define I2C_ENABLE_STDR (0x00000001 << 8)
+#define I2C_ENABLE_MTDR (0x00000001 << 7)
+#define I2C_ENABLE_IBE (0x00000001 << 6)
+#define I2C_ENABLE_MSMC (0x00000001 << 5)
+#define I2C_ENABLE_SRSD (0x00000001 << 4)
+#define I2C_ENABLE_STSD (0x00000001 << 3)
+#define I2C_ENABLE_MTNA (0x00000001 << 2)
+#define I2C_ENABLE_MAF (0x00000001 << 1)
+#define I2C_ENABLE_MTD (0x00000001 << 0)
+
+#define INT_CLR_STATUS 0xfe8
+#define I2C_CLR_STATUS_STFNF (0x00000001 << 12)
+#define I2C_CLR_STATUS_MTFNF (0x00000001 << 11)
+#define I2C_CLR_STATUS_RFDA (0x00000001 << 10)
+#define I2C_CLR_STATUS_RFF (0x00000001 << 9)
+#define I2C_CLR_STATUS_STDR (0x00000001 << 8)
+#define I2C_CLR_STATUS_MTDR (0x00000001 << 7)
+#define I2C_CLR_STATUS_IBE (0x00000001 << 6)
+#define I2C_CLR_STATUS_MSMC (0x00000001 << 5)
+#define I2C_CLR_STATUS_SRSD (0x00000001 << 4)
+#define I2C_CLR_STATUS_STSD (0x00000001 << 3)
+#define I2C_CLR_STATUS_MTNA (0x00000001 << 2)
+#define I2C_CLR_STATUS_MAF (0x00000001 << 1)
+#define I2C_CLR_STATIS_MTD (0x00000001 << 0)
+
+#define INT_SET_STATUS 0xfec
+#define I2C_SET_STATUS_STFNF (0x00000001 << 12)
+#define I2C_SET_STATUS_MTFNF (0x00000001 << 11)
+#define I2C_SET_STATUS_RFDA (0x00000001 << 10)
+#define I2C_SET_STATUS_RFF (0x00000001 << 9)
+#define I2C_SET_STATUS_STDR (0x00000001 << 8)
+#define I2C_SET_STATUS_MTDR (0x00000001 << 7)
+#define I2C_SET_STATUS_IBE (0x00000001 << 6)
+#define I2C_SET_STATUS_MSMC (0x00000001 << 5)
+#define I2C_SET_STATUS_SRSD (0x00000001 << 4)
+#define I2C_SET_STATUS_STSD (0x00000001 << 3)
+#define I2C_SET_STATUS_MTNA (0x00000001 << 2)
+#define I2C_SET_STATUS_MAF (0x00000001 << 1)
+#define I2C_SET_STATIS_MTD (0x00000001 << 0)
+
+
+#endif /* __SAA716x_I2C_REG_H */
diff --git a/drivers/media/common/saa716x/saa716x_mod.h b/drivers/media/common/saa716x/saa716x_mod.h
new file mode 100644
index 0000000..273efdd
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_mod.h
@@ -0,0 +1,50 @@
+#ifndef __SAA716x_MOD_H
+#define __SAA716x_MOD_H
+
+/* BAR = 17 bits */
+/*
+ VI0 0x00000000
+ VI1 0x00001000
+ FGPI0 0x00002000
+ FGPI1 0x00003000
+ FGPI2 0x00004000
+ FGPI3 0x00005000
+ AI0 0x00006000
+ AI1 0x00007000
+ BAM 0x00008000
+ MMU 0x00009000
+ MSI 0x0000a000
+ I2C_B 0x0000b000
+ I2C_A 0x0000c000
+ SPI 0x0000d000
+ GPIO 0x0000e000
+ PHI_0 0x0000f000
+ CGU 0x00013000
+ DCS 0x00014000
+ GREG 0x00012000
+
+ PHI_1 0x00020000
+*/
+
+#define VI0 0x00000000
+#define VI1 0x00001000
+#define FGPI0 0x00002000
+#define FGPI1 0x00003000
+#define FGPI2 0x00004000
+#define FGPI3 0x00005000
+#define AI0 0x00006000
+#define AI1 0x00007000
+#define BAM 0x00008000
+#define MMU 0x00009000
+#define MSI 0x0000a000
+#define I2C_B 0x0000b000
+#define I2C_A 0x0000c000
+#define SPI 0x0000d000
+#define GPIO 0x0000e000
+#define PHI_0 0x0000f000
+#define GREG 0x00012000
+#define CGU 0x00013000
+#define DCS 0x00014000
+#define PHI_1 0x00020000
+
+#endif /* __SAA716x_MOD_H */
diff --git a/drivers/media/common/saa716x/saa716x_msi.c b/drivers/media/common/saa716x/saa716x_msi.c
new file mode 100644
index 0000000..b0f05a2
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_msi.c
@@ -0,0 +1,479 @@
+#include <linux/delay.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "saa716x_mod.h"
+
+#include "saa716x_msi_reg.h"
+#include "saa716x_msi.h"
+#include "saa716x_spi.h"
+
+#include "saa716x_priv.h"
+
+#define SAA716x_MSI_VECTORS 50
+
+static const char *vector_name[] = {
+ "TAGACK_VI0_0",
+ "TAGACK_VI0_1",
+ "TAGACK_VI0_2",
+ "TAGACK_VI1_0",
+ "TAGACK_VI1_1",
+ "TAGACK_VI1_2",
+ "TAGACK_FGPI_0",
+ "TAGACK_FGPI_1",
+ "TAGACK_FGPI_2",
+ "TAGACK_FGPI_3",
+ "TAGACK_AI_0",
+ "TAGACK_AI_1",
+ "OVRFLW_VI0_0",
+ "OVRFLW_VI0_1",
+ "OVRFLW_VI0_2",
+ "OVRFLW_VI1_0",
+ "OVRFLW_VI1_1",
+ "OVRFLW_VI1_2",
+ "OVRFLW_FGPI_O",
+ "OVRFLW_FGPI_1",
+ "OVRFLW_FGPI_2",
+ "OVRFLW_FGPI_3",
+ "OVRFLW_AI_0",
+ "OVRFLW_AI_1",
+ "AVINT_VI0",
+ "AVINT_VI1",
+ "AVINT_FGPI_0",
+ "AVINT_FGPI_1",
+ "AVINT_FGPI_2",
+ "AVINT_FGPI_3",
+ "AVINT_AI_0",
+ "AVINT_AI_1",
+ "UNMAPD_TC_INT",
+ "EXTINT_0",
+ "EXTINT_1",
+ "EXTINT_2",
+ "EXTINT_3",
+ "EXTINT_4",
+ "EXTINT_5",
+ "EXTINT_6",
+ "EXTINT_7",
+ "EXTINT_8",
+ "EXTINT_9",
+ "EXTINT_10",
+ "EXTINT_11",
+ "EXTINT_12",
+ "EXTINT_13",
+ "EXTINT_14",
+ "EXTINT_15",
+ "I2CINT_0",
+ "I2CINT_1"
+};
+
+static u32 MSI_CONFIG_REG[51] = {
+ MSI_CONFIG0,
+ MSI_CONFIG1,
+ MSI_CONFIG2,
+ MSI_CONFIG3,
+ MSI_CONFIG4,
+ MSI_CONFIG5,
+ MSI_CONFIG6,
+ MSI_CONFIG7,
+ MSI_CONFIG8,
+ MSI_CONFIG9,
+ MSI_CONFIG10,
+ MSI_CONFIG11,
+ MSI_CONFIG12,
+ MSI_CONFIG13,
+ MSI_CONFIG14,
+ MSI_CONFIG15,
+ MSI_CONFIG16,
+ MSI_CONFIG17,
+ MSI_CONFIG18,
+ MSI_CONFIG19,
+ MSI_CONFIG20,
+ MSI_CONFIG21,
+ MSI_CONFIG22,
+ MSI_CONFIG23,
+ MSI_CONFIG24,
+ MSI_CONFIG25,
+ MSI_CONFIG26,
+ MSI_CONFIG27,
+ MSI_CONFIG28,
+ MSI_CONFIG29,
+ MSI_CONFIG30,
+ MSI_CONFIG31,
+ MSI_CONFIG32,
+ MSI_CONFIG33,
+ MSI_CONFIG34,
+ MSI_CONFIG35,
+ MSI_CONFIG36,
+ MSI_CONFIG37,
+ MSI_CONFIG38,
+ MSI_CONFIG39,
+ MSI_CONFIG40,
+ MSI_CONFIG41,
+ MSI_CONFIG42,
+ MSI_CONFIG43,
+ MSI_CONFIG44,
+ MSI_CONFIG45,
+ MSI_CONFIG46,
+ MSI_CONFIG47,
+ MSI_CONFIG48,
+ MSI_CONFIG49,
+ MSI_CONFIG50
+};
+
+int saa716x_msi_event(struct saa716x_dev *saa716x, u32 stat_l, u32 stat_h)
+{
+ dprintk(SAA716x_DEBUG, 0, "%s: MSI event ", __func__);
+
+ if (stat_l & MSI_INT_TAGACK_VI0_0)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[0]);
+
+ if (stat_l & MSI_INT_TAGACK_VI0_1)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[1]);
+
+ if (stat_l & MSI_INT_TAGACK_VI0_2)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[2]);
+
+ if (stat_l & MSI_INT_TAGACK_VI1_0)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[3]);
+
+ if (stat_l & MSI_INT_TAGACK_VI1_1)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[4]);
+
+ if (stat_l & MSI_INT_TAGACK_VI1_2)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[5]);
+
+ if (stat_l & MSI_INT_TAGACK_FGPI_0)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[6]);
+
+ if (stat_l & MSI_INT_TAGACK_FGPI_1)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[7]);
+
+ if (stat_l & MSI_INT_TAGACK_FGPI_2)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[8]);
+
+ if (stat_l & MSI_INT_TAGACK_FGPI_3)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[9]);
+
+ if (stat_l & MSI_INT_TAGACK_AI_0)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[10]);
+
+ if (stat_l & MSI_INT_TAGACK_AI_1)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[11]);
+
+ if (stat_l & MSI_INT_OVRFLW_VI0_0)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[12]);
+
+ if (stat_l & MSI_INT_OVRFLW_VI0_1)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[13]);
+
+ if (stat_l & MSI_INT_OVRFLW_VI0_2)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[14]);
+
+ if (stat_l & MSI_INT_OVRFLW_VI1_0)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[15]);
+
+ if (stat_l & MSI_INT_OVRFLW_VI1_1)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[16]);
+
+ if (stat_l & MSI_INT_OVRFLW_VI1_2)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[17]);
+
+ if (stat_l & MSI_INT_OVRFLW_FGPI_0)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[18]);
+
+ if (stat_l & MSI_INT_OVRFLW_FGPI_1)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[19]);
+
+ if (stat_l & MSI_INT_OVRFLW_FGPI_2)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[20]);
+
+ if (stat_l & MSI_INT_OVRFLW_FGPI_3)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[21]);
+
+ if (stat_l & MSI_INT_OVRFLW_AI_0)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[22]);
+
+ if (stat_l & MSI_INT_OVRFLW_AI_1)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[23]);
+
+ if (stat_l & MSI_INT_AVINT_VI0)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[24]);
+
+ if (stat_l & MSI_INT_AVINT_VI1)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[25]);
+
+ if (stat_l & MSI_INT_AVINT_FGPI_0)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[26]);
+
+ if (stat_l & MSI_INT_AVINT_FGPI_1)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[27]);
+
+ if (stat_l & MSI_INT_AVINT_FGPI_2)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[28]);
+
+ if (stat_l & MSI_INT_AVINT_FGPI_3)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[29]);
+
+ if (stat_l & MSI_INT_AVINT_AI_0)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[30]);
+
+ if (stat_l & MSI_INT_AVINT_AI_1)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[31]);
+
+ if (stat_h & MSI_INT_UNMAPD_TC_INT)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[32]);
+
+ if (stat_h & MSI_INT_EXTINT_0)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[33]);
+
+ if (stat_h & MSI_INT_EXTINT_1)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[34]);
+
+ if (stat_h & MSI_INT_EXTINT_2)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[35]);
+
+ if (stat_h & MSI_INT_EXTINT_3)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[36]);
+
+ if (stat_h & MSI_INT_EXTINT_4)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[37]);
+
+ if (stat_h & MSI_INT_EXTINT_5)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[38]);
+
+ if (stat_h & MSI_INT_EXTINT_6)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[39]);
+
+ if (stat_h & MSI_INT_EXTINT_7)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[40]);
+
+ if (stat_h & MSI_INT_EXTINT_8)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[41]);
+
+ if (stat_h & MSI_INT_EXTINT_9)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[42]);
+
+ if (stat_h & MSI_INT_EXTINT_10)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[43]);
+
+ if (stat_h & MSI_INT_EXTINT_11)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[44]);
+
+ if (stat_h & MSI_INT_EXTINT_12)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[45]);
+
+ if (stat_h & MSI_INT_EXTINT_13)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[46]);
+
+ if (stat_h & MSI_INT_EXTINT_14)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[47]);
+
+ if (stat_h & MSI_INT_EXTINT_15)
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[48]);
+
+ if (stat_h & MSI_INT_I2CINT_0) {
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[49]);
+ saa716x_i2c_irqevent(saa716x, 0);
+ }
+
+ if (stat_h & MSI_INT_I2CINT_1) {
+ dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[50]);
+ saa716x_i2c_irqevent(saa716x, 1);
+ }
+
+ dprintk(SAA716x_DEBUG, 0, "\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa716x_msi_event);
+
+int saa716x_msi_init(struct saa716x_dev *saa716x)
+{
+ u32 ena_l, ena_h, sta_l, sta_h, mid;
+ int i;
+
+ dprintk(SAA716x_DEBUG, 1, "Initializing MSI ..");
+ saa716x->handlers = 0;
+
+ /* get module id & version */
+ mid = SAA716x_EPRD(MSI, MSI_MODULE_ID);
+ if (mid != 0x30100)
+ dprintk(SAA716x_ERROR, 1, "MSI Id<%04x> is not supported", mid);
+
+ /* let HW take care of MSI race */
+ SAA716x_EPWR(MSI, MSI_DELAY_TIMER, 0x0);
+
+ /* INTA Polarity: Active High */
+ SAA716x_EPWR(MSI, MSI_INTA_POLARITY, MSI_INTA_POLARITY_HIGH);
+
+ /*
+ * IRQ Edge Rising: 25:24 = 0x01
+ * Traffic Class: 18:16 = 0x00
+ * MSI ID: 4:0 = 0x00
+ */
+ for (i = 0; i < SAA716x_MSI_VECTORS; i++)
+ SAA716x_EPWR(MSI, MSI_CONFIG_REG[i], MSI_INT_POL_EDGE_RISE);
+
+ /* get Status */
+ ena_l = SAA716x_EPRD(MSI, MSI_INT_ENA_L);
+ ena_h = SAA716x_EPRD(MSI, MSI_INT_ENA_H);
+ sta_l = SAA716x_EPRD(MSI, MSI_INT_STATUS_L);
+ sta_h = SAA716x_EPRD(MSI, MSI_INT_STATUS_H);
+
+ /* disable and clear enabled and asserted IRQ's */
+ if (sta_l)
+ SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_L, sta_l);
+
+ if (sta_h)
+ SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_H, sta_h);
+
+ if (ena_l)
+ SAA716x_EPWR(MSI, MSI_INT_ENA_CLR_L, ena_l);
+
+ if (ena_h)
+ SAA716x_EPWR(MSI, MSI_INT_ENA_CLR_H, ena_h);
+
+ msleep(5);
+
+ /* Check IRQ's really disabled */
+ ena_l = SAA716x_EPRD(MSI, MSI_INT_ENA_L);
+ ena_h = SAA716x_EPRD(MSI, MSI_INT_ENA_H);
+ sta_l = SAA716x_EPRD(MSI, MSI_INT_STATUS_L);
+ sta_h = SAA716x_EPRD(MSI, MSI_INT_STATUS_H);
+
+ if ((ena_l == 0) && (ena_h == 0) && (sta_l == 0) && (sta_h == 0)) {
+ dprintk(SAA716x_DEBUG, 1, "Interrupts ena_l <%02x> ena_h <%02x> sta_l <%02x> sta_h <%02x>",
+ ena_l, ena_h, sta_l, sta_h);
+
+ return 0;
+ } else {
+ dprintk(SAA716x_DEBUG, 1, "I/O error");
+ return -EIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa716x_msi_init);
+
+void saa716x_msiint_disable(struct saa716x_dev *saa716x)
+{
+ dprintk(SAA716x_DEBUG, 1, "Disabling Interrupts ...");
+
+ SAA716x_EPWR(MSI, MSI_INT_ENA_L, 0x0);
+ SAA716x_EPWR(MSI, MSI_INT_ENA_H, 0x0);
+ SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_L, 0xffffffff);
+ SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_L, 0x0000ffff);
+}
+EXPORT_SYMBOL_GPL(saa716x_msiint_disable);
+
+
+/* Map the given vector Id to the hardware bitmask. */
+static void saa716x_map_vector(struct saa716x_dev *saa716x, int vector, u32 *mask_l, u32 *mask_h)
+{
+ u32 tmp = 1;
+
+ if (vector < 32) {
+ /* Bits 0 - 31 */
+ tmp <<= vector;
+ *mask_l = tmp;
+ *mask_h = 0;
+ } else {
+ /* Bits 32 - 48 */
+ tmp <<= vector - 32;
+ *mask_l = 0;
+ *mask_h = tmp;
+ }
+}
+
+int saa716x_add_irqvector(struct saa716x_dev *saa716x,
+ int vector,
+ enum saa716x_edge edge,
+ irqreturn_t (*handler)(int irq, void *dev_id),
+ char *desc)
+{
+ struct saa716x_msix_entry *msix_handler = NULL;
+
+ u32 config, mask_l, mask_h, ena_l, ena_h;
+
+ BUG_ON(saa716x == NULL);
+ BUG_ON(vector > SAA716x_MSI_VECTORS);
+ dprintk(SAA716x_DEBUG, 1, "Adding Vector %d <%s>", vector, vector_name[vector]);
+
+ if ((vector > 32) && (vector < 49)) {
+ config = SAA716x_EPRD(MSI, MSI_CONFIG_REG[vector]);
+ config &= 0xfcffffff; /* clear polarity */
+
+ switch (edge) {
+ default:
+ case SAA716x_EDGE_RISING:
+ SAA716x_EPWR(MSI, MSI_CONFIG_REG[vector], config | 0x01000000);
+ break;
+
+ case SAA716x_EDGE_FALLING:
+ SAA716x_EPWR(MSI, MSI_CONFIG_REG[vector], config | 0x02000000);
+ break;
+
+ case SAA716x_EDGE_ANY:
+ SAA716x_EPWR(MSI, MSI_CONFIG_REG[vector], config | 0x03000000);
+ break;
+ }
+ }
+
+ saa716x_map_vector(saa716x, vector, &mask_l, &mask_h);
+
+ /* add callback */
+ msix_handler = &saa716x->saa716x_msix_handler[saa716x->handlers];
+ strcpy(msix_handler->desc, desc);
+ msix_handler->vector = vector;
+ msix_handler->handler = handler;
+ saa716x->handlers++;
+
+ SAA716x_EPWR(MSI, MSI_INT_ENA_SET_L, mask_l);
+ SAA716x_EPWR(MSI, MSI_INT_ENA_SET_H, mask_h);
+
+ ena_l = SAA716x_EPRD(MSI, MSI_INT_ENA_L);
+ ena_h = SAA716x_EPRD(MSI, MSI_INT_ENA_H);
+ dprintk(SAA716x_DEBUG, 1, "Interrupts ena_l <%02x> ena_h <%02x>", ena_l, ena_h);
+
+ return 0;
+}
+
+int saa716x_remove_irqvector(struct saa716x_dev *saa716x, int vector)
+{
+ struct saa716x_msix_entry *msix_handler;
+ int i;
+ u32 mask_l, mask_h;
+
+ msix_handler = &saa716x->saa716x_msix_handler[saa716x->handlers];
+ BUG_ON(msix_handler == NULL);
+ dprintk(SAA716x_DEBUG, 1, "Removing Vector %d <%s>", vector, vector_name[vector]);
+
+ /* loop through the registered handlers */
+ for (i = 0; i < saa716x->handlers; i++) {
+
+ /* we found our vector */
+ if (msix_handler->vector == vector) {
+ BUG_ON(msix_handler->handler == NULL); /* no handler yet */
+ dprintk(SAA716x_DEBUG, 1, "Vector %d <%s> removed",
+ msix_handler->vector,
+ msix_handler->desc);
+
+ /* check whether it is already released */
+ if (msix_handler->handler) {
+ msix_handler->vector = 0;
+ msix_handler->handler = NULL;
+ saa716x->handlers--;
+ }
+ }
+ }
+
+ saa716x_map_vector(saa716x, vector, &mask_l, &mask_h);
+
+ /* disable vector */
+ SAA716x_EPWR(MSI, MSI_INT_ENA_CLR_L, mask_l);
+ SAA716x_EPWR(MSI, MSI_INT_ENA_CLR_H, mask_h);
+
+ return 0;
+}
diff --git a/drivers/media/common/saa716x/saa716x_msi.h b/drivers/media/common/saa716x/saa716x_msi.h
new file mode 100644
index 0000000..8eb72d7
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_msi.h
@@ -0,0 +1,87 @@
+#ifndef __SAA716x_MSI_H
+#define __SAA716x_MSI_H
+
+#define TAGACK_VI0_0 0x000
+#define TAGACK_VI0_1 0x001
+#define TAGACK_VI0_2 0x002
+#define TAGACK_VI1_0 0x003
+#define TAGACK_VI1_1 0x004
+#define TAGACK_VI1_2 0x005
+#define TAGACK_FGPI_0 0x006
+#define TAGACK_FGPI_1 0x007
+#define TAGACK_FGPI_2 0x008
+#define TAGACK_FGPI_3 0x009
+#define TAGACK_AI_0 0x00a
+#define TAGACK_AI_1 0x00b
+#define OVRFLW_VI0_0 0x00c
+#define OVRFLW_VI0_1 0x00d
+#define OVRFLW_VI0_2 0x00e
+#define OVRFLW_VI1_0 0x00f
+#define OVRFLW_VI1_1 0x010
+#define OVRFLW_VI1_2 0x011
+#define OVRFLW_FGPI_O 0x012
+#define OVRFLW_FGPI_1 0x013
+#define OVRFLW_FGPI_2 0x014
+#define OVRFLW_FGPI_3 0x015
+#define OVRFLW_AI_0 0x016
+#define OVRFLW_AI_1 0x017
+#define AVINT_VI0 0x018
+#define AVINT_VI1 0x019
+#define AVINT_FGPI_0 0x01a
+#define AVINT_FGPI_1 0x01b
+#define AVINT_FGPI_2 0x01c
+#define AVINT_FGPI_3 0x01d
+#define AVINT_AI_0 0x01e
+#define AVINT_AI_1 0x01f
+#define UNMAPD_TC_INT 0x020
+#define EXTINT_0 0x021
+#define EXTINT_1 0x022
+#define EXTINT_2 0x023
+#define EXTINT_3 0x024
+#define EXTINT_4 0x025
+#define EXTINT_5 0x026
+#define EXTINT_6 0x027
+#define EXTINT_7 0x028
+#define EXTINT_8 0x029
+#define EXTINT_9 0x02a
+#define EXTINT_10 0x02b
+#define EXTINT_11 0x02c
+#define EXTINT_12 0x02d
+#define EXTINT_13 0x02e
+#define EXTINT_14 0x02f
+#define EXTINT_15 0x030
+#define I2CINT_0 0x031
+#define I2CINT_1 0x032
+
+#define SAA716x_TC0 0x000
+#define SAA716x_TC1 0x001
+#define SAA716x_TC2 0x002
+#define SAA716x_TC3 0x003
+#define SAA716x_TC4 0x004
+#define SAA716x_TC5 0x005
+#define SAA716x_TC6 0x006
+#define SAA716x_TC7 0x007
+
+
+enum saa716x_edge {
+ SAA716x_EDGE_RISING = 1,
+ SAA716x_EDGE_FALLING = 2,
+ SAA716x_EDGE_ANY = 3
+};
+
+struct saa716x_dev;
+
+extern int saa716x_msi_event(struct saa716x_dev *saa716x, u32 stat_l, u32 stat_h);
+
+extern int saa716x_msi_init(struct saa716x_dev *saa716x);
+extern void saa716x_msiint_disable(struct saa716x_dev *saa716x);
+
+extern int saa716x_add_irqvector(struct saa716x_dev *saa716x,
+ int vector,
+ enum saa716x_edge edge,
+ irqreturn_t (*handler)(int irq, void *dev_id),
+ char *desc);
+
+extern int saa716x_remove_irqvector(struct saa716x_dev *saa716x, int vector);
+
+#endif /* __SAA716x_MSI_H */
diff --git a/drivers/media/common/saa716x/saa716x_msi_reg.h b/drivers/media/common/saa716x/saa716x_msi_reg.h
new file mode 100644
index 0000000..d9a12c7
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_msi_reg.h
@@ -0,0 +1,143 @@
+#ifndef __SAA716x_MSI_REG_H
+#define __SAA716x_MSI_REG_H
+
+/* -------------- MSI Registers -------------- */
+
+#define MSI_DELAY_TIMER 0x000
+#define MSI_DELAY_1CLK (0x00000001 << 0)
+#define MSI_DELAY_2CLK (0x00000002 << 0)
+
+#define MSI_INTA_POLARITY 0x004
+#define MSI_INTA_POLARITY_HIGH (0x00000001 << 0)
+
+#define MSI_CONFIG0 0x008
+#define MSI_CONFIG1 0x00c
+#define MSI_CONFIG2 0x010
+#define MSI_CONFIG3 0x014
+#define MSI_CONFIG4 0x018
+#define MSI_CONFIG5 0x01c
+#define MSI_CONFIG6 0x020
+#define MSI_CONFIG7 0x024
+#define MSI_CONFIG8 0x028
+#define MSI_CONFIG9 0x02c
+#define MSI_CONFIG10 0x030
+#define MSI_CONFIG11 0x034
+#define MSI_CONFIG12 0x038
+#define MSI_CONFIG13 0x03c
+#define MSI_CONFIG14 0x040
+#define MSI_CONFIG15 0x044
+#define MSI_CONFIG16 0x048
+#define MSI_CONFIG17 0x04c
+#define MSI_CONFIG18 0x050
+#define MSI_CONFIG19 0x054
+#define MSI_CONFIG20 0x058
+#define MSI_CONFIG21 0x05c
+#define MSI_CONFIG22 0x060
+#define MSI_CONFIG23 0x064
+#define MSI_CONFIG24 0x068
+#define MSI_CONFIG25 0x06c
+#define MSI_CONFIG26 0x070
+#define MSI_CONFIG27 0x074
+#define MSI_CONFIG28 0x078
+#define MSI_CONFIG29 0x07c
+#define MSI_CONFIG30 0x080
+#define MSI_CONFIG31 0x084
+#define MSI_CONFIG32 0x088
+#define MSI_CONFIG33 0x08c
+#define MSI_CONFIG34 0x090
+#define MSI_CONFIG35 0x094
+#define MSI_CONFIG36 0x098
+#define MSI_CONFIG37 0x09c
+#define MSI_CONFIG38 0x0a0
+#define MSI_CONFIG39 0x0a4
+#define MSI_CONFIG40 0x0a8
+#define MSI_CONFIG41 0x0ac
+#define MSI_CONFIG42 0x0b0
+#define MSI_CONFIG43 0x0b4
+#define MSI_CONFIG44 0x0b8
+#define MSI_CONFIG45 0x0bc
+#define MSI_CONFIG46 0x0c0
+#define MSI_CONFIG47 0x0c4
+#define MSI_CONFIG48 0x0c8
+#define MSI_CONFIG49 0x0cc
+#define MSI_CONFIG50 0x0d0
+
+#define MSI_INT_POL_EDGE_RISE (0x00000001 << 24)
+#define MSI_INT_POL_EDGE_FALL (0x00000002 << 24)
+#define MSI_INT_POL_EDGE_ANY (0x00000003 << 24)
+#define MSI_TC (0x00000007 << 16)
+#define MSI_ID (0x0000000f << 0)
+
+#define MSI_INT_STATUS_L 0xfc0
+#define MSI_INT_TAGACK_VI0_0 (0x00000001 << 0)
+#define MSI_INT_TAGACK_VI0_1 (0x00000001 << 1)
+#define MSI_INT_TAGACK_VI0_2 (0x00000001 << 2)
+#define MSI_INT_TAGACK_VI1_0 (0x00000001 << 3)
+#define MSI_INT_TAGACK_VI1_1 (0x00000001 << 4)
+#define MSI_INT_TAGACK_VI1_2 (0x00000001 << 5)
+#define MSI_INT_TAGACK_FGPI_0 (0x00000001 << 6)
+#define MSI_INT_TAGACK_FGPI_1 (0x00000001 << 7)
+#define MSI_INT_TAGACK_FGPI_2 (0x00000001 << 8)
+#define MSI_INT_TAGACK_FGPI_3 (0x00000001 << 9)
+#define MSI_INT_TAGACK_AI_0 (0x00000001 << 10)
+#define MSI_INT_TAGACK_AI_1 (0x00000001 << 11)
+#define MSI_INT_OVRFLW_VI0_0 (0x00000001 << 12)
+#define MSI_INT_OVRFLW_VI0_1 (0x00000001 << 13)
+#define MSI_INT_OVRFLW_VI0_2 (0x00000001 << 14)
+#define MSI_INT_OVRFLW_VI1_0 (0x00000001 << 15)
+#define MSI_INT_OVRFLW_VI1_1 (0x00000001 << 16)
+#define MSI_INT_OVRFLW_VI1_2 (0x00000001 << 17)
+#define MSI_INT_OVRFLW_FGPI_0 (0x00000001 << 18)
+#define MSI_INT_OVRFLW_FGPI_1 (0x00000001 << 19)
+#define MSI_INT_OVRFLW_FGPI_2 (0x00000001 << 20)
+#define MSI_INT_OVRFLW_FGPI_3 (0x00000001 << 21)
+#define MSI_INT_OVRFLW_AI_0 (0x00000001 << 22)
+#define MSI_INT_OVRFLW_AI_1 (0x00000001 << 23)
+#define MSI_INT_AVINT_VI0 (0x00000001 << 24)
+#define MSI_INT_AVINT_VI1 (0x00000001 << 25)
+#define MSI_INT_AVINT_FGPI_0 (0x00000001 << 26)
+#define MSI_INT_AVINT_FGPI_1 (0x00000001 << 27)
+#define MSI_INT_AVINT_FGPI_2 (0x00000001 << 28)
+#define MSI_INT_AVINT_FGPI_3 (0x00000001 << 29)
+#define MSI_INT_AVINT_AI_0 (0x00000001 << 30)
+#define MSI_INT_AVINT_AI_1 (0x00000001 << 31)
+
+#define MSI_INT_STATUS_H 0xfc4
+#define MSI_INT_UNMAPD_TC_INT (0x00000001 << 0)
+#define MSI_INT_EXTINT_0 (0x00000001 << 1)
+#define MSI_INT_EXTINT_1 (0x00000001 << 2)
+#define MSI_INT_EXTINT_2 (0x00000001 << 3)
+#define MSI_INT_EXTINT_3 (0x00000001 << 4)
+#define MSI_INT_EXTINT_4 (0x00000001 << 5)
+#define MSI_INT_EXTINT_5 (0x00000001 << 6)
+#define MSI_INT_EXTINT_6 (0x00000001 << 7)
+#define MSI_INT_EXTINT_7 (0x00000001 << 8)
+#define MSI_INT_EXTINT_8 (0x00000001 << 9)
+#define MSI_INT_EXTINT_9 (0x00000001 << 10)
+#define MSI_INT_EXTINT_10 (0x00000001 << 11)
+#define MSI_INT_EXTINT_11 (0x00000001 << 12)
+#define MSI_INT_EXTINT_12 (0x00000001 << 13)
+#define MSI_INT_EXTINT_13 (0x00000001 << 14)
+#define MSI_INT_EXTINT_14 (0x00000001 << 15)
+#define MSI_INT_EXTINT_15 (0x00000001 << 16)
+#define MSI_INT_I2CINT_0 (0x00000001 << 17)
+#define MSI_INT_I2CINT_1 (0x00000001 << 18)
+
+#define MSI_INT_STATUS_CLR_L 0xfc8
+#define MSI_INT_STATUS_CLR_H 0xfcc
+#define MSI_INT_STATUS_SET_L 0xfd0
+#define MSI_INT_STATUS_SET_H 0xfd4
+#define MSI_INT_ENA_L 0xfd8
+#define MSI_INT_ENA_H 0xfdc
+#define MSI_INT_ENA_CLR_L 0xfe0
+#define MSI_INT_ENA_CLR_H 0xfe4
+#define MSI_INT_ENA_SET_L 0xfe8
+#define MSI_INT_ENA_SET_H 0xfec
+
+#define MSI_SW_RST 0xff0
+#define MSI_SW_RESET (0x0001 << 0)
+
+#define MSI_MODULE_ID 0xffc
+
+
+#endif /* __SAA716x_MSI_REG_H */
diff --git a/drivers/media/common/saa716x/saa716x_pci.c b/drivers/media/common/saa716x/saa716x_pci.c
new file mode 100644
index 0000000..7fa6bad
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_pci.c
@@ -0,0 +1,275 @@
+#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/delay.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "saa716x_spi.h"
+#include "saa716x_msi.h"
+#include "saa716x_priv.h"
+
+#define DRIVER_NAME "SAA716x Core"
+
+static irqreturn_t saa716x_msi_handler(int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+
+static int saa716x_enable_msi(struct saa716x_dev *saa716x)
+{
+ struct pci_dev *pdev = saa716x->pdev;
+ int err;
+
+ err = pci_enable_msi(pdev);
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "MSI enable failed <%d>", err);
+ return err;
+ }
+
+ return err;
+}
+
+static int saa716x_enable_msix(struct saa716x_dev *saa716x)
+{
+ struct pci_dev *pdev = saa716x->pdev;
+ int i, ret = 0;
+
+ for (i = 0; i < SAA716x_MSI_MAX_VECTORS; i++)
+ saa716x->msix_entries[i].entry = i;
+
+ ret = pci_enable_msix(pdev, saa716x->msix_entries, SAA716x_MSI_MAX_VECTORS);
+ if (ret < 0)
+ dprintk(SAA716x_ERROR, 1, "MSI-X request failed <%d>", ret);
+ if (ret > 0)
+ dprintk(SAA716x_ERROR, 1, "Request exceeds available IRQ's <%d>", ret);
+
+ return ret;
+}
+
+static int saa716x_request_irq(struct saa716x_dev *saa716x)
+{
+ struct pci_dev *pdev = saa716x->pdev;
+ struct saa716x_config *config = saa716x->config;
+ int i, ret = 0;
+
+ if (saa716x->int_type == MODE_MSI) {
+ dprintk(SAA716x_DEBUG, 1, "Using MSI mode");
+ ret = saa716x_enable_msi(saa716x);
+ } else if (saa716x->int_type == MODE_MSI_X) {
+ dprintk(SAA716x_DEBUG, 1, "Using MSI-X mode");
+ ret = saa716x_enable_msix(saa716x);
+ }
+
+ if (ret) {
+ dprintk(SAA716x_ERROR, 1, "INT-A Mode");
+ saa716x->int_type = MODE_INTA;
+ }
+
+ if (saa716x->int_type == MODE_MSI) {
+ ret = request_irq(pdev->irq,
+ config->irq_handler,
+ 0,
+ DRIVER_NAME,
+ saa716x);
+
+ if (ret) {
+ pci_disable_msi(pdev);
+ dprintk(SAA716x_ERROR, 1, "MSI registration failed");
+ ret = -EIO;
+ }
+ }
+
+ if (saa716x->int_type == MODE_MSI_X) {
+ for (i = 0; SAA716x_MSI_MAX_VECTORS; i++) {
+ ret = request_irq(saa716x->msix_entries[i].vector,
+ saa716x->saa716x_msix_handler[i].handler,
+ IRQF_SHARED,
+ saa716x->saa716x_msix_handler[i].desc,
+ saa716x);
+
+ dprintk(SAA716x_ERROR, 1, "%s @ 0x%p", saa716x->saa716x_msix_handler[i].desc, saa716x->saa716x_msix_handler[i].handler);
+ if (ret) {
+ dprintk(SAA716x_ERROR, 1, "%s MSI-X-%d registration failed <%d>", saa716x->saa716x_msix_handler[i].desc, i, ret);
+ return -1;
+ }
+ }
+ }
+
+ if (saa716x->int_type == MODE_INTA) {
+ ret = request_irq(pdev->irq,
+ config->irq_handler,
+ IRQF_SHARED,
+ DRIVER_NAME,
+ saa716x);
+ if (ret < 0) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x IRQ registration failed <%d>", ret);
+ ret = -ENODEV;
+ }
+ }
+
+ return ret;
+}
+
+static void saa716x_free_irq(struct saa716x_dev *saa716x)
+{
+ struct pci_dev *pdev = saa716x->pdev;
+ int i, vector;
+
+ if (saa716x->int_type == MODE_MSI_X) {
+
+ for (i = 0; i < SAA716x_MSI_MAX_VECTORS; i++) {
+ vector = saa716x->msix_entries[i].vector;
+ free_irq(vector, saa716x);
+ }
+
+ pci_disable_msix(pdev);
+
+ } else {
+ free_irq(pdev->irq, saa716x);
+ if (saa716x->int_type == MODE_MSI)
+ pci_disable_msi(pdev);
+ }
+}
+
+int saa716x_pci_init(struct saa716x_dev *saa716x)
+{
+ struct pci_dev *pdev = saa716x->pdev;
+ int err = 0, ret = -ENODEV, i, use_dac, pm_cap;
+ u32 msi_cap;
+ u8 revision;
+
+ dprintk(SAA716x_ERROR, 1, "found a %s PCIe card", saa716x->config->model_name);
+
+ err = pci_enable_device(pdev);
+ if (err != 0) {
+ ret = -ENODEV;
+ dprintk(SAA716x_ERROR, 1, "ERROR: PCI enable failed (%i)", err);
+ goto fail0;
+ }
+
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ use_dac = 1;
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (err) {
+ dprintk(SAA716x_ERROR, 1, "Unable to obtain 64bit DMA");
+ goto fail1;
+ }
+ } else if ((err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
+ dprintk(SAA716x_ERROR, 1, "Unable to obtain 32bit DMA");
+ goto fail1;
+ }
+
+ pci_set_master(pdev);
+
+ pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (pm_cap == 0) {
+ dprintk(SAA716x_ERROR, 1, "Cannot find Power Management Capability");
+ err = -EIO;
+ goto fail1;
+ }
+
+ if (!request_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0),
+ DRIVER_NAME)) {
+
+ dprintk(SAA716x_ERROR, 1, "BAR0 Request failed");
+ ret = -ENODEV;
+ goto fail1;
+ }
+ saa716x->mmio = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+
+ if (!saa716x->mmio) {
+ dprintk(SAA716x_ERROR, 1, "Mem 0 remap failed");
+ ret = -ENODEV;
+ goto fail2;
+ }
+
+ for (i = 0; i < SAA716x_MSI_MAX_VECTORS; i++)
+ saa716x->msix_entries[i].entry = i;
+
+ err = saa716x_request_irq(saa716x);
+ if (err < 0) {
+ dprintk(SAA716x_ERROR, 1, "SAA716x IRQ registration failed, err=%d", err);
+ ret = -ENODEV;
+ goto fail3;
+ }
+
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+ pci_read_config_dword(pdev, 0x40, &msi_cap);
+
+ saa716x->revision = revision;
+
+ dprintk(SAA716x_ERROR, 0, " SAA%02x Rev %d [%04x:%04x], ",
+ saa716x->pdev->device,
+ revision,
+ saa716x->pdev->subsystem_vendor,
+ saa716x->pdev->subsystem_device);
+
+ dprintk(SAA716x_ERROR, 0,
+ "irq: %d,\n mmio: 0x%p\n",
+ saa716x->pdev->irq,
+ saa716x->mmio);
+
+ dprintk(SAA716x_ERROR, 0, " SAA%02x %sBit, MSI %s, MSI-X=%d msgs",
+ saa716x->pdev->device,
+ (((msi_cap >> 23) & 0x01) == 1 ? "64":"32"),
+ (((msi_cap >> 16) & 0x01) == 1 ? "Enabled" : "Disabled"),
+ (1 << ((msi_cap >> 17) & 0x07)));
+
+ dprintk(SAA716x_ERROR, 0, "\n");
+
+ pci_set_drvdata(pdev, saa716x);
+
+ return 0;
+
+fail3:
+ dprintk(SAA716x_ERROR, 1, "Err: IO Unmap");
+ if (saa716x->mmio)
+ iounmap(saa716x->mmio);
+fail2:
+ dprintk(SAA716x_ERROR, 1, "Err: Release regions");
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+
+fail1:
+ dprintk(SAA716x_ERROR, 1, "Err: Disabling device");
+ pci_disable_device(pdev);
+
+fail0:
+ pci_set_drvdata(pdev, NULL);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(saa716x_pci_init);
+
+void saa716x_pci_exit(struct saa716x_dev *saa716x)
+{
+ struct pci_dev *pdev = saa716x->pdev;
+
+ saa716x_free_irq(saa716x);
+
+ dprintk(SAA716x_NOTICE, 1, "SAA%02x mem0: 0x%p",
+ saa716x->pdev->device,
+ saa716x->mmio);
+
+ if (saa716x->mmio) {
+ iounmap(saa716x->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(saa716x_pci_exit);
+
+MODULE_DESCRIPTION("SAA716x bridge driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/saa716x/saa716x_phi.c b/drivers/media/common/saa716x/saa716x_phi.c
new file mode 100644
index 0000000..7df9a98
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_phi.c
@@ -0,0 +1,152 @@
+#include <linux/kernel.h>
+
+#include "saa716x_mod.h"
+
+#include "saa716x_phi_reg.h"
+
+#include "saa716x_spi.h"
+#include "saa716x_phi.h"
+#include "saa716x_priv.h"
+
+u32 PHI_0_REGS[] = {
+ PHI_0_MODE,
+ PHI_0_0_CONFIG,
+ PHI_0_1_CONFIG,
+ PHI_0_2_CONFIG,
+ PHI_0_3_CONFIG
+};
+
+u32 PHI_1_REGS[] = {
+ PHI_1_MODE,
+ PHI_1_0_CONFIG,
+ PHI_1_1_CONFIG,
+ PHI_1_2_CONFIG,
+ PHI_1_3_CONFIG,
+ PHI_1_4_CONFIG,
+ PHI_1_5_CONFIG,
+ PHI_1_6_CONFIG,
+ PHI_1_7_CONFIG
+};
+
+#define PHI_BASE(__port) (( \
+ (__port == PHI_1) ? \
+ PHI_1_BASE : \
+ PHI_0_BASE \
+))
+
+#define PHI_APERTURE(_port) (( \
+ (__port == PHI_1) ? \
+ PHI_1_APERTURE: \
+ PHI_0_APERTURE \
+))
+
+#define PHI_REG(__port, __reg) (( \
+ (__port == PHI_1) ? \
+ PHI_1_REGS[__reg] : \
+ PHI_0_REGS[__reg] \
+))
+
+#define PHI_SLAVE(__port, __slave) (( \
+ PHI_BASE(__port) + (__slave * (PHI_APERTURE(__port))) \
+))
+
+/* // Read SAA716x registers
+ * SAA716x_EPRD(PHI_0, PHI_REG(__port, __reg))
+ * SAA716x_EPWR(PHI_1, PHI_REG(__port, __reg), __data)
+ *
+ * // Read slave registers
+ * SAA716x_EPRD(PHI_0, PHI_SLAVE(__port, __slave, __offset))
+ * SAA716x_EPWR(PHI_1, PHI_SLAVE(__port, __slave, _offset), __data)
+ */
+
+int saa716x_init_phi(struct saa716x_dev *saa716x, u32 port, u8 slave)
+{
+ int i;
+
+ /* Reset */
+ SAA716x_EPWR(PHI_0, PHI_SW_RST, 0x1);
+
+ for (i = 0; i < 20; i++) {
+ msleep(1);
+ if (!(SAA716x_EPRD(PHI_0, PHI_SW_RST)))
+ break;
+ }
+
+ return 0;
+}
+
+int saa716x_phi_init(struct saa716x_dev *saa716x)
+{
+ uint32_t value;
+
+ /* init PHI 0 to FIFO mode */
+ value = 0;
+ value |= PHI_FIFO_MODE;
+ SAA716x_EPWR(PHI_0, PHI_0_MODE, value);
+
+ value = 0;
+ value |= 0x02; /* chip select 1 */
+ value |= 0x00 << 8; /* ready mask */
+ value |= 0x03 << 12; /* strobe time */
+ value |= 0x06 << 20; /* cycle time */
+ SAA716x_EPWR(PHI_0, PHI_0_0_CONFIG, value);
+
+ /* init PHI 1 to SRAM mode, auto increment on */
+ value = 0;
+ value |= PHI_AUTO_INCREMENT;
+ SAA716x_EPWR(PHI_0, PHI_1_MODE, value);
+
+ value = 0;
+ value |= 0x01; /* chip select 0 */
+ value |= 0x00 << 8; /* ready mask */
+ value |= 0x03 << 12; /* strobe time */
+ value |= 0x05 << 20; /* cycle time */
+ SAA716x_EPWR(PHI_0, PHI_1_0_CONFIG, value);
+
+ value = 0;
+ value |= PHI_ALE_POL; /* ALE is active high */
+ SAA716x_EPWR(PHI_0, PHI_POLARITY, value);
+
+ SAA716x_EPWR(PHI_0, PHI_TIMEOUT, 0x2a);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa716x_phi_init);
+
+int saa716x_phi_write(struct saa716x_dev *saa716x, u32 address, const u8 * data, int length)
+{
+ int i;
+
+ for (i = 0; i < length; i += 4) {
+ SAA716x_EPWR(PHI_1, address, *((u32 *) &data[i]));
+ address += 4;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa716x_phi_write);
+
+int saa716x_phi_read(struct saa716x_dev *saa716x, u32 address, u8 * data, int length)
+{
+ int i;
+
+ for (i = 0; i < length; i += 4) {
+ *((u32 *) &data[i]) = SAA716x_EPRD(PHI_1, address);
+ address += 4;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa716x_phi_read);
+
+int saa716x_phi_write_fifo(struct saa716x_dev *saa716x, const u8 * data, int length)
+{
+ int i;
+
+ for (i = 0; i < length; i += 4) {
+ SAA716x_EPWR(PHI_0, PHI_0_0_RW_0, *((u32 *) &data[i]));
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa716x_phi_write_fifo);
diff --git a/drivers/media/common/saa716x/saa716x_phi.h b/drivers/media/common/saa716x/saa716x_phi.h
new file mode 100644
index 0000000..ff5cda2
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_phi.h
@@ -0,0 +1,39 @@
+#ifndef __SAA716x_PHI_H
+#define __SAA716x_PHI_H
+
+/* PHI SLAVE */
+#define PHI_SLAVE_0 0
+#define PHI_SLAVE_1 1
+#define PHI_SLAVE_2 2
+#define PHI_SLAVE_3 3
+#define PHI_SLAVE_4 4
+#define PHI_SLAVE_5 5
+#define PHI_SLAVE_6 6
+#define PHI_SLAVE_7 7
+
+/* PHI_REG */
+#define PHI_MODE 0
+#define PHI_CONFIG_0 1
+#define PHI_CONFIG_1 2
+#define PHI_CONFIG_2 3
+#define PHI_CONFIG_3 4
+#define PHI_CONFIG_4 5
+#define PHI_CONFIG_5 6
+#define PHI_CONFIG_6 7
+#define PHI_CONFIG_7 8
+
+#define PHI_0_BASE 0x1000
+#define PHI_0_APERTURE 0x0800
+
+#define PHI_1_BASE 0x0000
+#define PHI_1_APERTURE 0xfffc
+
+struct saa716x_dev;
+
+extern int saa716x_init_phi(struct saa716x_dev *saa716x, u32 port, u8 slave);
+extern int saa716x_phi_init(struct saa716x_dev *saa716x);
+extern int saa716x_phi_write(struct saa716x_dev *saa716x, u32 address, const u8 *data, int length);
+extern int saa716x_phi_read(struct saa716x_dev *saa716x, u32 address, u8 *data, int length);
+extern int saa716x_phi_write_fifo(struct saa716x_dev *saa716x, const u8 * data, int length);
+
+#endif /* __SAA716x_PHI_H */
diff --git a/drivers/media/common/saa716x/saa716x_phi_reg.h b/drivers/media/common/saa716x/saa716x_phi_reg.h
new file mode 100644
index 0000000..08f0aa7
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_phi_reg.h
@@ -0,0 +1,100 @@
+#ifndef __SAA716x_PHI_REG_H
+#define __SAA716x_PHI_REG_H
+
+/* -------------- PHI_0 Registers -------------- */
+
+#define PHI_0_MODE 0x0000
+#define PHI_0_0_CONFIG 0x0008
+#define PHI_0_1_CONFIG 0x000c
+#define PHI_0_2_CONFIG 0x0010
+#define PHI_0_3_CONFIG 0x0014
+
+#define PHI_POLARITY 0x0038
+#define PHI_TIMEOUT 0x003c
+#define PHI_SW_RST 0x0ff0
+
+#define PHI_0_0_RW_0 0x1000
+#define PHI_0_0_RW_511 0x17fc
+
+#define PHI_0_1_RW_0 0x1800
+#define PHI_0_1_RW_511 0x1ffc
+
+#define PHI_0_2_RW_0 0x2000
+#define PHI_0_2_RW_511 0x27fc
+
+#define PHI_0_3_RW_0 0x2800
+#define PHI_0_3_RW_511 0x2ffc
+
+#define PHI_CSN_DEASSERT (0x00000001 << 2)
+#define PHI_AUTO_INCREMENT (0x00000001 << 1)
+#define PHI_FIFO_MODE (0x00000001 << 0)
+
+#define PHI_DELAY_RD_WR (0x0000001f << 27)
+#define PHI_EXTEND_RDY3 (0x00000003 << 25)
+#define PHI_EXTEND_RDY2 (0x00000003 << 23)
+#define PHI_EXTEND_RDY1 (0x00000003 << 21)
+#define PHI_EXTEND_RDY0 (0x00000003 << 19)
+#define PHI_RDY3_OD (0x00000001 << 18)
+#define PHI_RDY2_OD (0x00000001 << 17)
+#define PHI_RDY1_OD (0x00000001 << 16)
+#define PHI_RDY0_OD (0x00000001 << 15)
+#define PHI_ALE_POL (0x00000001 << 14)
+#define PHI_WRN_POL (0x00000001 << 13)
+#define PHI_RDN_POL (0x00000001 << 12)
+#define PHI_RDY3_POL (0x00000001 << 11)
+#define PHI_RDY2_POL (0x00000001 << 10)
+#define PHI_RDY1_POL (0x00000001 << 9)
+#define PHI_RDY0_POL (0x00000001 << 8)
+#define PHI_CSN7_POL (0x00000001 << 7)
+#define PHI_CSN6_POL (0x00000001 << 6)
+#define PHI_CSN5_POL (0x00000001 << 5)
+#define PHI_CSN4_POL (0x00000001 << 4)
+#define PHI_CSN3_POL (0x00000001 << 3)
+#define PHI_CSN2_POL (0x00000001 << 2)
+#define PHI_CSN1_POL (0x00000001 << 1)
+#define PHI_CSN0_POL (0x00000001 << 0)
+
+/* -------------- PHI_1 Registers -------------- */
+
+#define PHI_1 0x00020000
+
+#define PHI_1_MODE 0x00004
+#define PHI_1_0_CONFIG 0x00018
+#define PHI_1_1_CONFIG 0x0001c
+#define PHI_1_2_CONFIG 0x00020
+#define PHI_1_3_CONFIG 0x00024
+#define PHI_1_4_CONFIG 0x00028
+#define PHI_1_5_CONFIG 0x0002c
+#define PHI_1_6_CONFIG 0x00030
+#define PHI_1_7_CONFIG 0x00034
+
+#define PHI_1_0_RW_0 0x00000
+#define PHI_1_0_RW_16383 0x0fffc
+
+#define PHI_1_1_RW_0 0x1000
+#define PHI_1_1_RW_16383 0x1ffc
+
+#define PHI_1_2_RW_0 0x2000
+#define PHI_1_2_RW_16383 0x2ffc
+
+#define PHI_1_3_RW_0 0x3000
+#define PHI_1_3_RW_16383 0x3ffc
+
+#define PHI_1_4_RW_0 0x4000
+#define PHI_1_4_RW_16383 0x4ffc
+
+#define PHI_1_5_RW_0 0x5000
+#define PHI_1_5_RW_16383 0x5ffc
+
+#define PHI_1_6_RW_0 0x6000
+#define PHI_1_6_RW_16383 0x6ffc
+
+#define PHI_1_7_RW_0 0x7000
+#define PHI_1_7_RW_16383 0x7ffc
+
+
+/* BAR = 20 bits */
+/* -------------- PHI1 Registers -------------- */
+
+
+#endif /* __SAA716x_PHI_REG_H */
diff --git a/drivers/media/common/saa716x/saa716x_priv.h b/drivers/media/common/saa716x/saa716x_priv.h
new file mode 100644
index 0000000..1ad1d9c
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_priv.h
@@ -0,0 +1,194 @@
+#ifndef __SAA716x_PRIV_H
+#define __SAA716x_PRIV_H
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include "saa716x_i2c.h"
+#include "saa716x_boot.h"
+#include "saa716x_cgu.h"
+#include "saa716x_dma.h"
+#include "saa716x_fgpi.h"
+
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dmxdev.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#define SAA716x_ERROR 0
+#define SAA716x_NOTICE 1
+#define SAA716x_INFO 2
+#define SAA716x_DEBUG 3
+
+#define SAA716x_DEV (saa716x)->num
+#define SAA716x_VERBOSE (saa716x)->verbose
+#define SAA716x_MAX_ADAPTERS 4
+
+#define dprintk(__x, __y, __fmt, __arg...) do { \
+ if (__y) { \
+ if ((SAA716x_VERBOSE > SAA716x_ERROR) && (SAA716x_VERBOSE > __x)) \
+ printk(KERN_ERR "%s (%d): " __fmt "\n" , __func__ , SAA716x_DEV , ##__arg); \
+ else if ((SAA716x_VERBOSE > SAA716x_NOTICE) && (SAA716x_VERBOSE > __x)) \
+ printk(KERN_NOTICE "%s (%d): " __fmt "\n" , __func__ , SAA716x_DEV , ##__arg); \
+ else if ((SAA716x_VERBOSE > SAA716x_INFO) && (SAA716x_VERBOSE > __x)) \
+ printk(KERN_INFO "%s (%d): " __fmt "\n" , __func__ , SAA716x_DEV , ##__arg); \
+ else if ((SAA716x_VERBOSE > SAA716x_DEBUG) && (SAA716x_VERBOSE > __x)) \
+ printk(KERN_DEBUG "%s (%d): " __fmt "\n" , __func__ , SAA716x_DEV , ##__arg); \
+ } else { \
+ if (SAA716x_VERBOSE > __x) \
+ printk(__fmt , ##__arg); \
+ } \
+} while(0)
+
+
+#define NXP_SEMICONDUCTOR 0x1131
+#define SAA7160 0x7160
+#define SAA7161 0x7161
+#define SAA7162 0x7162
+
+#define NXP_REFERENCE_BOARD 0x1131
+
+#define MAKE_ENTRY(__subven, __subdev, __chip, __configptr) { \
+ .vendor = NXP_SEMICONDUCTOR, \
+ .device = (__chip), \
+ .subvendor = (__subven), \
+ .subdevice = (__subdev), \
+ .driver_data = (unsigned long) (__configptr) \
+}
+
+#define SAA716x_EPWR(__offst, __addr, __data) writel((__data), (saa716x->mmio + (__offst + __addr)))
+#define SAA716x_EPRD(__offst, __addr) readl((saa716x->mmio + (__offst + __addr)))
+
+#define SAA716x_RCWR(__offst, __addr, __data) writel((__data), (saa716x->mmio + (__offst + __addr)))
+#define SAA716x_RCRD(__offst, __addr) readl((saa716x->mmio + (__offst + __addr)))
+
+
+#define SAA716x_MSI_MAX_VECTORS 16
+
+struct saa716x_msix_entry {
+ int vector;
+ u8 desc[32];
+ irqreturn_t (*handler)(int irq, void *dev_id);
+};
+
+struct saa716x_dev;
+struct saa716x_adapter;
+struct saa716x_spi_config;
+
+struct saa716x_adap_config {
+ u32 ts_port;
+ void (*worker)(unsigned long);
+};
+
+struct saa716x_config {
+ char *model_name;
+ char *dev_type;
+
+ enum saa716x_boot_mode boot_mode;
+
+ int adapters;
+ int frontends;
+
+ int (*frontend_attach)(struct saa716x_adapter *adapter, int count);
+ irqreturn_t (*irq_handler)(int irq, void *dev_id);
+
+ struct saa716x_adap_config adap_config[SAA716x_MAX_ADAPTERS];
+ enum saa716x_i2c_rate i2c_rate;
+ enum saa716x_i2c_mode i2c_mode;
+};
+
+struct saa716x_adapter {
+ 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 dvb_net;
+
+ struct saa716x_dev *saa716x;
+
+ u8 feeds;
+ u8 count;
+};
+
+struct saa716x_dev {
+ struct saa716x_config *config;
+ struct pci_dev *pdev;
+
+ int num; /* device count */
+ int verbose;
+
+ u8 revision;
+
+ /* PCI */
+ void __iomem *mmio;
+
+#define MODE_INTA 0
+#define MODE_MSI 1
+#define MODE_MSI_X 2
+ u8 int_type;
+
+ struct msix_entry msix_entries[SAA716x_MSI_MAX_VECTORS];
+ struct saa716x_msix_entry saa716x_msix_handler[56];
+ u8 handlers; /* no. of active handlers */
+
+ /* I2C */
+ struct saa716x_i2c i2c[2];
+ u32 i2c_rate; /* init time */
+ u32 I2C_DEV[2];
+
+ struct saa716x_spi_state *saa716x_spi;
+ struct saa716x_spi_config spi_config;
+
+ struct saa716x_adapter saa716x_adap[SAA716x_MAX_ADAPTERS];
+ struct mutex adap_lock;
+ struct saa716x_cgu cgu;
+
+ spinlock_t gpio_lock;
+ /* DMA */
+
+ struct saa716x_fgpi_stream_port fgpi[4];
+
+ u32 id_offst;
+ u32 id_len;
+ void *priv;
+
+ /* remote control */
+ void *ir_priv;
+};
+
+/* PCI */
+extern int saa716x_pci_init(struct saa716x_dev *saa716x);
+extern void saa716x_pci_exit(struct saa716x_dev *saa716x);
+
+/* MSI */
+extern int saa716x_msi_init(struct saa716x_dev *saa716x);
+extern void saa716x_msi_exit(struct saa716x_dev *saa716x);
+extern void saa716x_msiint_disable(struct saa716x_dev *saa716x);
+
+/* DMA */
+extern int saa716x_dma_init(struct saa716x_dev *saa716x);
+extern void saa716x_dma_exit(struct saa716x_dev *saa716x);
+
+/* AUDIO */
+extern int saa716x_audio_init(struct saa716x_dev *saa716x);
+extern void saa716x_audio_exit(struct saa716x_dev *saa716x);
+
+/* Boot */
+extern int saa716x_core_boot(struct saa716x_dev *saa716x);
+extern int saa716x_jetpack_init(struct saa716x_dev *saa716x);
+
+/* Remote control */
+extern int saa716x_ir_init(struct saa716x_dev *saa716x);
+extern void saa716x_ir_exit(struct saa716x_dev *saa716x);
+extern void saa716x_ir_handler(struct saa716x_dev *saa716x, u32 ir_cmd);
+
+#endif /* __SAA716x_PRIV_H */
diff --git a/drivers/media/common/saa716x/saa716x_reg.h b/drivers/media/common/saa716x/saa716x_reg.h
new file mode 100644
index 0000000..effd966
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_reg.h
@@ -0,0 +1,1279 @@
+#ifndef __SAA716x_REG_H
+#define __SAA716x_REG_H
+
+/* BAR = 17 bits */
+/*
+ VI0 0x00000000
+ VI1 0x00001000
+ FGPI0 0x00002000
+ FGPI1 0x00003000
+ FGPI2 0x00004000
+ FGPI3 0x00005000
+ AI0 0x00006000
+ AI1 0x00007000
+ BAM 0x00008000
+ MMU 0x00009000
+ MSI 0x0000a000
+ I2C_B 0x0000b000
+ I2C_A 0x0000c000
+ SPI 0x0000d000
+ GPIO 0x0000e000
+ PHI_0 0x0000f000
+ CGU 0x00013000
+ DCS 0x00014000
+ GREG 0x00012000
+
+ PHI_1 0x00020000
+*/
+
+/* -------------- VIP Registers -------------- */
+
+#define VI0 0x00000000
+#define VI1 0x00001000
+
+#define VI_MODE 0x000
+#define VID_CFEN (0x00000003 << 30)
+#define VID_OSM (0x00000001 << 29)
+#define VID_FSEQ (0x00000001 << 28)
+#define AUX_CFEN (0x00000003 << 26)
+#define AUX_OSM (0x00000001 << 25)
+#define AUX_FSEQ (0x00000001 << 24)
+#define AUX_ANC_DATA (0x00000003 << 22)
+#define AUX_ANC_RAW (0x00000001 << 21)
+#define RST_ON_ERR (0x00000001 << 17)
+#define SOFT_RESET (0x00000001 << 16)
+#define IFF_CLAMP (0x00000001 << 14)
+#define IFF_MODE (0x00000003 << 12)
+#define DFF_CLAMP (0x00000001 << 10)
+#define DFF_MODE (0x00000003 << 8)
+#define HSP_CLAMP (0x00000001 << 3)
+#define HSP_RGB (0x00000001 << 2)
+#define HSP_MODE (0x00000003 << 0)
+
+#define RCRB_CTRL 0x004
+#define RCRB_CFG_ADDR 0x008
+#define RCRB_CFG_EXT_ADDR 0x00c
+#define RCRB_IO_ADDR 0x010
+#define RCRB_MEM_LADDR 0x014
+#define RCRB_MEM_UADDR 0x018
+#define RCRB_DATA 0x01c
+#define RCRB_MASK 0x020
+#define RCRB_MSG_HDR 0x040
+#define RCRB_MSG_PL0 0x044
+#define RCRB_MSG_PL1 0x048
+
+#define ID_MASK0 0x020
+#define VI_ID_MASK_0 (0x000000ff << 8)
+#define VI_DATA_ID_0 (0x000000ff << 0)
+
+#define ID_MASK1 0x024
+#define VI_ID_MASK_1 (0x000000ff << 8)
+#define VI_DATA_ID_1 (0x000000ff << 0)
+
+#define VIP_LINE_THRESH 0x040
+#define VI_LCTHR (0x000007ff << 0)
+
+#define VIN_FORMAT 0x100
+#define VI_VSRA (0x00000003 << 30)
+#define VI_SYNCHD (0x00000001 << 25)
+#define VI_DUAL_STREAM (0x00000001 << 24)
+#define VI_NHDAUX (0x00000001 << 20)
+#define VI_NPAR (0x00000001 << 19)
+#define VI_VSEL (0x00000003 << 14)
+#define VI_TWOS (0x00000001 << 13)
+#define VI_TPG (0x00000001 << 12)
+#define VI_FREF (0x00000001 << 10)
+#define VI_FTGL (0x00000001 << 9)
+#define VI_SF (0x00000001 << 3)
+#define VI_FZERO (0x00000001 << 2)
+#define VI_REVS (0x00000001 << 1)
+#define VI_REHS (0x00000001 << 0)
+
+#define TC76543210 0x800
+#define TCFEDCBA98 0x804
+#define PHYCFG 0x900
+#define CONFIG 0xfd4
+#define INT_ENABLE_CLR 0xfd8
+#define INT_ENABLE_SET 0xfdc
+
+
+#define INT_STATUS 0xfe0
+#define VI_STAT_FID_AUX (0x00000001 << 31)
+#define VI_STAT_FID_VID (0x00000001 << 30)
+#define VI_STAT_FID_VPI (0x00000001 << 29)
+#define VI_STAT_LINE_COUNT (0x00000fff << 16)
+#define VI_STAT_AUX_OVRFLW (0x00000001 << 9)
+#define VI_STAT_VID_OVRFLW (0x00000001 << 8)
+#define VI_STAT_WIN_SEQBRK (0x00000001 << 7)
+#define VI_STAT_FID_SEQBRK (0x00000001 << 6)
+#define VI_STAT_LINE_THRESH (0x00000001 << 5)
+#define VI_STAT_AUX_WRAP (0x00000001 << 4)
+#define VI_STAT_AUX_START_IN (0x00000001 << 3)
+#define VI_STAT_AUX_END_OUT (0x00000001 << 2)
+#define VI_STAT_VID_START_IN (0x00000001 << 1)
+#define VI_STAT_VID_END_OUT (0x00000001 << 0)
+
+#define INT_ENABLE 0xfe4
+#define VI_ENABLE_AUX_OVRFLW (0x00000001 << 9)
+#define VI_ENABLE_VID_OVRFLW (0x00000001 << 8)
+#define VI_ENABLE_WIN_SEQBRK (0x00000001 << 7)
+#define VI_ENABLE_FID_SEQBRK (0x00000001 << 6)
+#define VI_ENABLE_LINE_THRESH (0x00000001 << 5)
+#define VI_ENABLE_AUX_WRAP (0x00000001 << 4)
+#define VI_ENABLE_AUX_START_IN (0x00000001 << 3)
+#define VI_ENABLE_AUX_END_OUT (0x00000001 << 2)
+#define VI_ENABLE_VID_START_IN (0x00000001 << 1)
+#define VI_ENABLE_VID_END_OUT (0x00000001 << 0)
+
+#define INT_CLR_STATUS 0xfe8
+#define VI_CLR_STATUS_AUX_OVRFLW (0x00000001 << 9)
+#define VI_CLR_STATUS_VID_OVRFLW (0x00000001 << 8)
+#define VI_CLR_STATUS_WIN_SEQBRK (0x00000001 << 7)
+#define VI_CLR_STATUS_FID_SEQBRK (0x00000001 << 6)
+#define VI_CLR_STATUS_LINE_THRESH (0x00000001 << 5)
+#define VI_CLR_STATUS_AUX_WRAP (0x00000001 << 4)
+#define VI_CLR_STATUS_AUX_START_IN (0x00000001 << 3)
+#define VI_CLR_STATUS_AUX_END_OUT (0x00000001 << 2)
+#define VI_CLR_STATUS_VID_START_IN (0x00000001 << 1)
+#define VI_CLR_STATUS_VID_END_OUT (0x00000001 << 0)
+
+#define INT_SET_STATUS 0xfec
+#define VI_SET_STATUS_AUX_OVRFLW (0x00000001 << 9)
+#define VI_SET_STATUS_VID_OVRFLW (0x00000001 << 8)
+#define VI_SET_STATUS_WIN_SEQBRK (0x00000001 << 7)
+#define VI_SET_STATUS_FID_SEQBRK (0x00000001 << 6)
+#define VI_SET_STATUS_LINE_THRESH (0x00000001 << 5)
+#define VI_SET_STATUS_AUX_WRAP (0x00000001 << 4)
+#define VI_SET_STATUS_AUX_START_IN (0x00000001 << 3)
+#define VI_SET_STATUS_AUX_END_OUT (0x00000001 << 2)
+#define VI_SET_STATUS_VID_START_IN (0x00000001 << 1)
+#define VI_SET_STATUS_VID_END_OUT (0x00000001 << 0)
+
+#define VIP_POWER_DOWN 0xff4
+#define VI_PWR_DWN (0x00000001 << 31)
+
+
+
+
+/* -------------- FGPI Registers -------------- */
+
+#define FGPI0 0x00002000
+#define FGPI1 0x00003000
+#define FGPI2 0x00004000
+#define FGPI3 0x00005000
+
+#define FGPI_CONTROL 0x000
+#define FGPI_CAPTURE_ENABLE_2 (0x00000001 << 13)
+#define FGPI_CAPTURE_ENABLE_1 (0x00000001 << 12)
+#define FGPI_MODE (0x00000001 << 11)
+#define FGPI_SAMPLE_SIZE (0x00000003 << 8)
+#define FGPI_BUF_SYNC_MSG_STOP (0x00000003 << 5)
+#define FGPI_REC_START_MSG_START (0x00000003 << 2)
+#define FGPI_TSTAMP_SELECT (0x00000001 << 1)
+#define FGPI_VAR_LENGTH (0x00000001 << 0)
+
+#define FGPI_BASE_1 0x004
+#define FGPI_BASE_2 0x008
+#define FGPI_SIZE 0x00c
+#define FGPI_REC_SIZE 0x010
+#define FGPI_STRIDE 0x014
+#define FGPI_NUM_RECORD_1 0x018
+#define FGPI_NUM_RECORD_2 0x01c
+#define FGPI_THRESHOLD_1 0x020
+#define FGPI_THRESHOLD_2 0x024
+#define FGPI_D1_XY_START 0x028
+#define FGPI_D1_XY_END 0x02c
+
+#define INT_STATUS 0xfe0
+#define FGPI_BUF1_ACTIVE (0x00000001 << 7)
+#define FGPI_OVERFLOW (0x00000001 << 6)
+#define FGPI_MBE (0x00000001 << 5)
+#define FGPI_UNDERRUN (0x00000001 << 4)
+#define FGPI_THRESH2_REACHED (0x00000001 << 3)
+#define FGPI_THRESH1_REACHED (0x00000001 << 2)
+#define FGPI_BUF2_FULL (0x00000001 << 1)
+#define FGPI_BUF1_FULL (0x00000001 << 0)
+
+#define INT_ENABLE 0xfe4
+#define FGPI_OVERFLOW_ENA (0x00000001 << 6)
+#define FGPI_MBE_ENA (0x00000001 << 5)
+#define FGPI_UNDERRUN_ENA (0x00000001 << 4)
+#define FGPI_THRESH2_REACHED_ENA (0x00000001 << 3)
+#define FGPI_THRESH1_REACHED_ENA (0x00000001 << 2)
+#define FGPI_BUF2_FULL_ENA (0x00000001 << 1)
+#define FGPI_BUF1_FULL_ENA (0x00000001 << 0)
+
+#define INT_CLR_STATUS 0xfe8
+#define FGPI_OVERFLOW_ACK (0x00000001 << 6)
+#define FGPI_MBE_ACK (0x00000001 << 5)
+#define FGPI_UNDERRUN_ACK (0x00000001 << 4)
+#define FGPI_THRESH2_REACHED_ACK (0x00000001 << 3)
+#define FGPI_THRESH1_REACHED_ACK (0x00000001 << 2)
+#define FGPI_BUF2_DONE_ACK (0x00000001 << 1)
+#define FGPI_BUF1_DONE_ACK (0x00000001 << 0)
+
+#define INT_SET_STATUS 0xfec
+#define FGPI_OVERFLOW_SET (0x00000001 << 6)
+#define FGPI_MBE_SET (0x00000001 << 5)
+#define FGPI_UNDERRUN_SET (0x00000001 << 4)
+#define FGPI_THRESH2_REACHED_SET (0x00000001 << 3)
+#define FGPI_THRESH1_REACHED_SET (0x00000001 << 2)
+#define FGPI_BUF2_DONE_SET (0x00000001 << 1)
+#define FGPI_BUF1_DONE_SET (0x00000001 << 0)
+
+#define FGPI_SOFT_RESET 0xff0
+#define FGPI_SOFTWARE_RESET (0x00000001 << 0)
+
+#define FGPI_INTERFACE 0xff4
+#define FGPI_DISABLE_BUS_IF (0x00000001 << 0)
+
+#define FGPI_MOD_ID_EXT 0xff8
+#define FGPI_MODULE_ID 0xffc
+
+
+/* -------------- AI Registers ---------------- */
+
+#define AI0 0x00006000
+#define AI1 0x00007000
+
+#define AI_STATUS 0x000
+#define AI_BUF1_ACTIVE (0x00000001 << 4)
+#define AI_OVERRUN (0x00000001 << 3)
+#define AI_HBE (0x00000001 << 2)
+#define AI_BUF2_FULL (0x00000001 << 1)
+#define AI_BUF1_FULL (0x00000001 << 0)
+
+#define AI_CTL 0x004
+#define AI_RESET (0x00000001 << 31)
+#define AI_CAP_ENABLE (0x00000001 << 30)
+#define AI_CAP_MODE (0x00000003 << 28)
+#define AI_SIGN_CONVERT (0x00000001 << 27)
+#define AI_EARLYMODE (0x00000001 << 26)
+#define AI_DIAGMODE (0x00000001 << 25)
+#define AI_RAWMODE (0x00000001 << 24)
+#define AI_OVR_INTEN (0x00000001 << 7)
+#define AI_HBE_INTEN (0x00000001 << 6)
+#define AI_BUF2_INTEN (0x00000001 << 5)
+#define AI_BUF1_INTEN (0x00000001 << 4)
+#define AI_ACK_OVR (0x00000001 << 3)
+#define AI_ACK_HBE (0x00000001 << 2)
+#define AI_ACK2 (0x00000001 << 1)
+#define AI_ACK1 (0x00000001 << 0)
+
+#define AI_SERIAL 0x008
+#define AI_SER_MASTER (0x00000001 << 31)
+#define AI_DATAMODE (0x00000001 << 30)
+#define AI_FRAMEMODE (0x00000003 << 28)
+#define AI_CLOCK_EDGE (0x00000001 << 27)
+#define AI_SSPOS4 (0x00000001 << 19)
+#define AI_NR_CHAN (0x00000003 << 17)
+#define AI_WSDIV (0x000001ff << 8)
+#define AI_SCKDIV (0x000000ff << 0)
+
+#define AI_FRAMING 0x00c
+#define AI_VALIDPOS (0x000001ff << 22)
+#define AI_LEFTPOS (0x000001ff << 13)
+#define AI_RIGHTPOS (0x000001ff << 4)
+#define AI_SSPOS_3_0 (0x0000000f << 0)
+
+#define AI_BASE1 0x014
+#define AI_BASE2 0x018
+#define AI_BASE (0x03ffffff << 6)
+
+#define AI_SIZE 0x01c
+#define AI_SAMPLE_SIZE (0x03ffffff << 6)
+
+#define AI_INT_ACK 0x020
+#define AI_ACK_OVR (0x00000001 << 3)
+#define AI_ACK_HBE (0x00000001 << 2)
+#define AI_ACK2 (0x00000001 << 1)
+#define AI_ACK1 (0x00000001 << 0)
+
+#define AI_PWR_DOWN 0xff4
+#define AI_PWR_DWN (0x00000001 << 0)
+
+/* -------------- BAM Registers -------------- */
+
+#define BAM 0x00008000
+
+#define BAM_VI0_0_DMA_BUF_MODE 0x000
+
+#define BAM_VI0_0_ADDR_OFFST_0 0x004
+#define BAM_VI0_0_ADDR_OFFST_1 0x008
+#define BAM_VI0_0_ADDR_OFFST_2 0x00c
+#define BAM_VI0_0_ADDR_OFFST_3 0x010
+#define BAM_VI0_0_ADDR_OFFST_4 0x014
+#define BAM_VI0_0_ADDR_OFFST_5 0x018
+#define BAM_VI0_0_ADDR_OFFST_6 0x01c
+#define BAM_VI0_0_ADDR_OFFST_7 0x020
+
+#define BAM_VI0_1_DMA_BUF_MODE 0x024
+#define BAM_VI0_1_ADDR_OFFST_0 0x028
+#define BAM_VI0_1_ADDR_OFFST_1 0x02c
+#define BAM_VI0_1_ADDR_OFFST_2 0x030
+#define BAM_VI0_1_ADDR_OFFST_3 0x034
+#define BAM_VI0_1_ADDR_OFFST_4 0x038
+#define BAM_VI0_1_ADDR_OFFST_5 0x03c
+#define BAM_VI0_1_ADDR_OFFST_6 0x040
+#define BAM_VI0_1_ADDR_OFFST_7 0x044
+
+#define BAM_VI0_2_DMA_BUF_MODE 0x048
+#define BAM_VI0_2_ADDR_OFFST_0 0x04c
+#define BAM_VI0_2_ADDR_OFFST_1 0x050
+#define BAM_VI0_2_ADDR_OFFST_2 0x054
+#define BAM_VI0_2_ADDR_OFFST_3 0x058
+#define BAM_VI0_2_ADDR_OFFST_4 0x05c
+#define BAM_VI0_2_ADDR_OFFST_5 0x060
+#define BAM_VI0_2_ADDR_OFFST_6 0x064
+#define BAM_VI0_2_ADDR_OFFST_7 0x068
+
+
+#define BAM_VI1_0_DMA_BUF_MODE 0x06c
+#define BAM_VI1_0_ADDR_OFFST_0 0x070
+#define BAM_VI1_0_ADDR_OFFST_1 0x074
+#define BAM_VI1_0_ADDR_OFFST_2 0x078
+#define BAM_VI1_0_ADDR_OFFST_3 0x07c
+#define BAM_VI1_0_ADDR_OFFST_4 0x080
+#define BAM_VI1_0_ADDR_OFFST_5 0x084
+#define BAM_VI1_0_ADDR_OFFST_6 0x088
+#define BAM_VI1_0_ADDR_OFFST_7 0x08c
+
+#define BAM_VI1_1_DMA_BUF_MODE 0x090
+#define BAM_VI1_1_ADDR_OFFST_0 0x094
+#define BAM_VI1_1_ADDR_OFFST_1 0x098
+#define BAM_VI1_1_ADDR_OFFST_2 0x09c
+#define BAM_VI1_1_ADDR_OFFST_3 0x0a0
+#define BAM_VI1_1_ADDR_OFFST_4 0x0a4
+#define BAM_VI1_1_ADDR_OFFST_5 0x0a8
+#define BAM_VI1_1_ADDR_OFFST_6 0x0ac
+#define BAM_VI1_1_ADDR_OFFST_7 0x0b0
+
+#define BAM_VI1_2_DMA_BUF_MODE 0x0b4
+#define BAM_VI1_2_ADDR_OFFST_0 0x0b8
+#define BAM_VI1_2_ADDR_OFFST_1 0x0bc
+#define BAM_VI1_2_ADDR_OFFST_2 0x0c0
+#define BAM_VI1_2_ADDR_OFFST_3 0x0c4
+#define BAM_VI1_2_ADDR_OFFST_4 0x0c8
+#define BAM_VI1_2_ADDR_OFFST_5 0x0cc
+#define BAM_VI1_2_ADDR_OFFST_6 0x0d0
+#define BAM_VI1_2_ADDR_OFFST_7 0x0d4
+
+
+#define BAM_FGPI0_DMA_BUF_MODE 0x0d8
+#define BAM_FGPI0_ADDR_OFFST_0 0x0dc
+#define BAM_FGPI0_ADDR_OFFST_1 0x0e0
+#define BAM_FGPI0_ADDR_OFFST_2 0x0e4
+#define BAM_FGPI0_ADDR_OFFST_3 0x0e8
+#define BAM_FGPI0_ADDR_OFFST_4 0x0ec
+#define BAM_FGPI0_ADDR_OFFST_5 0x0f0
+#define BAM_FGPI0_ADDR_OFFST_6 0x0f4
+#define BAM_FGPI0_ADDR_OFFST_7 0x0f8
+
+#define BAM_FGPI1_DMA_BUF_MODE 0x0fc
+#define BAM_FGPI1_ADDR_OFFST_0 0x100
+#define BAM_FGPI1_ADDR_OFFST_1 0x104
+#define BAM_FGPI1_ADDR_OFFST_2 0x108
+#define BAM_FGPI1_ADDR_OFFST_3 0x10c
+#define BAM_FGPI1_ADDR_OFFST_4 0x110
+#define BAM_FGPI1_ADDR_OFFST_5 0x114
+#define BAM_FGPI1_ADDR_OFFST_6 0x118
+#define BAM_FGPI1_ADDR_OFFST_7 0x11c
+
+#define BAM_FGPI2_DMA_BUF_MODE 0x120
+#define BAM_FGPI2_ADDR_OFFST_0 0x124
+#define BAM_FGPI2_ADDR_OFFST_1 0x128
+#define BAM_FGPI2_ADDR_OFFST_2 0x12c
+#define BAM_FGPI2_ADDR_OFFST_3 0x130
+#define BAM_FGPI2_ADDR_OFFST_4 0x134
+#define BAM_FGPI2_ADDR_OFFST_5 0x138
+#define BAM_FGPI2_ADDR_OFFST_6 0x13c
+#define BAM_FGPI2_ADDR_OFFST_7 0x140
+
+#define BAM_FGPI3_DMA_BUF_MODE 0x144
+#define BAM_FGPI3_ADDR_OFFST_0 0x148
+#define BAM_FGPI3_ADDR_OFFST_1 0x14c
+#define BAM_FGPI3_ADDR_OFFST_2 0x150
+#define BAM_FGPI3_ADDR_OFFST_3 0x154
+#define BAM_FGPI3_ADDR_OFFST_4 0x158
+#define BAM_FGPI3_ADDR_OFFST_5 0x15c
+#define BAM_FGPI3_ADDR_OFFST_6 0x160
+#define BAM_FGPI3_ADDR_OFFST_7 0x164
+
+
+#define BAM_AI0_DMA_BUF_MODE 0x168
+#define BAM_AI0_ADDR_OFFST_0 0x16c
+#define BAM_AI0_ADDR_OFFST_1 0x170
+#define BAM_AI0_ADDR_OFFST_2 0x174
+#define BAM_AI0_ADDR_OFFST_3 0x178
+#define BAM_AI0_ADDR_OFFST_4 0x17c
+#define BAM_AIO_ADDR_OFFST_5 0x180
+#define BAM_AI0_ADDR_OFFST_6 0x184
+#define BAM_AIO_ADDR_OFFST_7 0x188
+
+#define BAM_AI1_DMA_BUF_MODE 0x18c
+#define BAM_AI1_ADDR_OFFST_0 0x190
+#define BAM_AI1_ADDR_OFFST_1 0x194
+#define BAM_AI1_ADDR_OFFST_2 0x198
+#define BAM_AI1_ADDR_OFFST_3 0x19c
+#define BAM_AI1_ADDR_OFFST_4 0x1a0
+#define BAM_AI1_ADDR_OFFST_5 0x1a4
+#define BAM_AI1_ADDR_OFFST_6 0x1a8
+#define BAM_AI1_ADDR_OFFST_7 0x1ac
+
+#define BAM_SW_RST 0xff0
+#define BAM_SW_RESET (0x00000001 << 0)
+
+
+
+
+
+/* -------------- MMU Registers -------------- */
+
+#define MMU 0x00009000
+
+#define MMU_MODE 0x000
+
+#define MMU_DMA_CONFIG0 0x004
+#define MMU_DMA_CONFIG1 0x008
+#define MMU_DMA_CONFIG2 0x00c
+#define MMU_DMA_CONFIG3 0x010
+#define MMU_DMA_CONFIG4 0x014
+#define MMU_DMA_CONFIG5 0x018
+#define MMU_DMA_CONFIG6 0x01c
+#define MMU_DMA_CONFIG7 0x020
+#define MMU_DMA_CONFIG8 0x024
+#define MMU_DMA_CONFIG9 0x028
+#define MMU_DMA_CONFIG10 0x02c
+#define MMU_DMA_CONFIG11 0x030
+#define MMU_DMA_CONFIG12 0x034
+#define MMU_DMA_CONFIG13 0x038
+#define MMU_DMA_CONFIG14 0x03c
+#define MMU_DMA_CONFIG15 0x040
+
+#define MMU_SW_RST 0xff0
+#define MMU_SW_RESET (0x0001 << 0)
+
+#define MMU_PTA_BASE0 0x044 /* DMA 0 */
+#define MMU_PTA_BASE1 0x084 /* DMA 1 */
+#define MMU_PTA_BASE2 0x0c4 /* DMA 2 */
+#define MMU_PTA_BASE3 0x104 /* DMA 3 */
+#define MMU_PTA_BASE4 0x144 /* DMA 4 */
+#define MMU_PTA_BASE5 0x184 /* DMA 5 */
+#define MMU_PTA_BASE6 0x1c4 /* DMA 6 */
+#define MMU_PTA_BASE7 0x204 /* DMA 7 */
+#define MMU_PTA_BASE8 0x244 /* DMA 8 */
+#define MMU_PTA_BASE9 0x284 /* DMA 9 */
+#define MMU_PTA_BASE10 0x2c4 /* DMA 10 */
+#define MMU_PTA_BASE11 0x304 /* DMA 11 */
+#define MMU_PTA_BASE12 0x344 /* DMA 12 */
+#define MMU_PTA_BASE13 0x384 /* DMA 13 */
+#define MMU_PTA_BASE14 0x3c4 /* DMA 14 */
+#define MMU_PTA_BASE15 0x404 /* DMA 15 */
+
+#define MMU_PTA_BASE 0x044 /* DMA 0 */
+#define MMU_PTA_OFFSET 0x40
+
+#define PTA_BASE(__ch) (MMU_PTA_BASE + (MMU_PTA_OFFSET * __ch))
+
+#define MMU_PTA0_LSB(__ch) PTA_BASE(__ch) + 0x00
+#define MMU_PTA0_MSB(__ch) PTA_BASE(__ch) + 0x04
+#define MMU_PTA1_LSB(__ch) PTA_BASE(__ch) + 0x08
+#define MMU_PTA1_MSB(__ch) PTA_BASE(__ch) + 0x0c
+#define MMU_PTA2_LSB(__ch) PTA_BASE(__ch) + 0x10
+#define MMU_PTA2_MSB(__ch) PTA_BASE(__ch) + 0x14
+#define MMU_PTA3_LSB(__ch) PTA_BASE(__ch) + 0x18
+#define MMU_PTA3_MSB(__ch) PTA_BASE(__ch) + 0x1c
+#define MMU_PTA4_LSB(__ch) PTA_BASE(__ch) + 0x20
+#define MMU_PTA4_MSB(__ch) PTA_BASE(__ch) + 0x24
+#define MMU_PTA5_LSB(__ch) PTA_BASE(__ch) + 0x28
+#define MMU_PTA5_MSB(__ch) PTA_BASE(__ch) + 0x2c
+#define MMU_PTA6_LSB(__ch) PTA_BASE(__ch) + 0x30
+#define MMU_PTA6_MSB(__ch) PTA_BASE(__ch) + 0x34
+#define MMU_PTA7_LSB(__ch) PTA_BASE(__ch) + 0x38
+#define MMU_PTA7_MSB(__ch) PTA_BASE(__ch) + 0x3c
+
+
+/* -------------- MSI Registers -------------- */
+
+#define MSI 0x0000a000
+
+#define MSI_DELAY_TIMER 0x000
+#define MSI_DELAY_1CLK (0x00000001 << 0)
+#define MSI_DELAY_2CLK (0x00000002 << 0)
+
+#define MSI_INTA_POLARITY 0x004
+#define MSI_INTA_POLARITY_HIGH (0x00000001 << 0)
+
+#define MSI_CONFIG0 0x008
+#define MSI_CONFIG1 0x00c
+#define MSI_CONFIG2 0x010
+#define MSI_CONFIG3 0x014
+#define MSI_CONFIG4 0x018
+#define MSI_CONFIG5 0x01c
+#define MSI_CONFIG6 0x020
+#define MSI_CONFIG7 0x024
+#define MSI_CONFIG8 0x028
+#define MSI_CONFIG9 0x02c
+#define MSI_CONFIG10 0x030
+#define MSI_CONFIG11 0x034
+#define MSI_CONFIG12 0x038
+#define MSI_CONFIG13 0x03c
+#define MSI_CONFIG14 0x040
+#define MSI_CONFIG15 0x044
+#define MSI_CONFIG16 0x048
+#define MSI_CONFIG17 0x04c
+#define MSI_CONFIG18 0x050
+#define MSI_CONFIG19 0x054
+#define MSI_CONFIG20 0x058
+#define MSI_CONFIG21 0x05c
+#define MSI_CONFIG22 0x060
+#define MSI_CONFIG23 0x064
+#define MSI_CONFIG24 0x068
+#define MSI_CONFIG25 0x06c
+#define MSI_CONFIG26 0x070
+#define MSI_CONFIG27 0x074
+#define MSI_CONFIG28 0x078
+#define MSI_CONFIG29 0x07c
+#define MSI_CONFIG30 0x080
+#define MSI_CONFIG31 0x084
+#define MSI_CONFIG32 0x088
+#define MSI_CONFIG33 0x08c
+#define MSI_CONFIG34 0x090
+#define MSI_CONFIG35 0x094
+#define MSI_CONFIG36 0x098
+#define MSI_CONFIG37 0x09c
+#define MSI_CONFIG38 0x0a0
+#define MSI_CONFIG39 0x0a4
+#define MSI_CONFIG40 0x0a8
+#define MSI_CONFIG41 0x0ac
+#define MSI_CONFIG42 0x0b0
+#define MSI_CONFIG43 0x0b4
+#define MSI_CONFIG44 0x0b8
+#define MSI_CONFIG45 0x0bc
+#define MSI_CONFIG46 0x0c0
+#define MSI_CONFIG47 0x0c4
+#define MSI_CONFIG48 0x0c8
+#define MSI_CONFIG49 0x0cc
+#define MSI_CONFIG50 0x0d0
+
+#define MSI_INT_POL_EDGE_RISE (0x00000001 << 24)
+#define MSI_INT_POL_EDGE_FALL (0x00000002 << 24)
+#define MSI_INT_POL_EDGE_ANY (0x00000003 << 24)
+#define MSI_TC (0x00000007 << 16)
+#define MSI_ID (0x0000000f << 0)
+
+#define MSI_INT_STATUS_L 0xfc0
+#define MSI_INT_TAGACK_VI0_0 (0x00000001 << 0)
+#define MSI_INT_TAGACK_VI0_1 (0x00000001 << 1)
+#define MSI_INT_TAGACK_VI0_2 (0x00000001 << 2)
+#define MSI_INT_TAGACK_VI1_0 (0x00000001 << 3)
+#define MSI_INT_TAGACK_VI1_1 (0x00000001 << 4)
+#define MSI_INT_TAGACK_VI1_2 (0x00000001 << 5)
+#define MSI_INT_TAGACK_FGPI_0 (0x00000001 << 6)
+#define MSI_INT_TAGACK_FGPI_1 (0x00000001 << 7)
+#define MSI_INT_TAGACK_FGPI_2 (0x00000001 << 8)
+#define MSI_INT_TAGACK_FGPI_3 (0x00000001 << 9)
+#define MSI_INT_TAGACK_AI_0 (0x00000001 << 10)
+#define MSI_INT_TAGACK_AI_1 (0x00000001 << 11)
+#define MSI_INT_OVRFLW_VI0_0 (0x00000001 << 12)
+#define MSI_INT_OVRFLW_VI0_1 (0x00000001 << 13)
+#define MSI_INT_OVRFLW_VI0_2 (0x00000001 << 14)
+#define MSI_INT_OVRFLW_VI1_0 (0x00000001 << 15)
+#define MSI_INT_OVRFLW_VI1_1 (0x00000001 << 16)
+#define MSI_INT_OVRFLW_VI1_2 (0x00000001 << 17)
+#define MSI_INT_OVRFLW_FGPI_O (0x00000001 << 18)
+#define MSI_INT_OVRFLW_FGPI_1 (0x00000001 << 19)
+#define MSI_INT_OVRFLW_FGPI_2 (0x00000001 << 20)
+#define MSI_INT_OVRFLW_FGPI_3 (0x00000001 << 21)
+#define MSI_INT_OVRFLW_AI_0 (0x00000001 << 22)
+#define MSI_INT_OVRFLW_AI_1 (0x00000001 << 23)
+#define MSI_INT_AVINT_VI0 (0x00000001 << 24)
+#define MSI_INT_AVINT_VI1 (0x00000001 << 25)
+#define MSI_INT_AVINT_FGPI_0 (0x00000001 << 26)
+#define MSI_INT_AVINT_FGPI_1 (0x00000001 << 27)
+#define MSI_INT_AVINT_FGPI_2 (0x00000001 << 28)
+#define MSI_INT_AVINT_FGPI_3 (0x00000001 << 29)
+#define MSI_INT_AVINT_AI_0 (0x00000001 << 30)
+#define MSI_INT_AVINT_AI_1 (0x00000001 << 31)
+
+#define MSI_INT_STATUS_H 0xfc4
+#define MSI_INT_UNMAPD_TC_INT (0x00000001 << 0)
+#define MSI_INT_EXTINT_0 (0x00000001 << 1)
+#define MSI_INT_EXTINT_1 (0x00000001 << 2)
+#define MSI_INT_EXTINT_2 (0x00000001 << 3)
+#define MSI_INT_EXTINT_3 (0x00000001 << 4)
+#define MSI_INT_EXTINT_4 (0x00000001 << 5)
+#define MSI_INT_EXTINT_5 (0x00000001 << 6)
+#define MSI_INT_EXTINT_6 (0x00000001 << 7)
+#define MSI_INT_EXTINT_7 (0x00000001 << 8)
+#define MSI_INT_EXTINT_8 (0x00000001 << 9)
+#define MSI_INT_EXTINT_9 (0x00000001 << 10)
+#define MSI_INT_EXTINT_10 (0x00000001 << 11)
+#define MSI_INT_EXTINT_11 (0x00000001 << 12)
+#define MSI_INT_EXTINT_12 (0x00000001 << 13)
+#define MSI_INT_EXTINT_13 (0x00000001 << 14)
+#define MSI_INT_EXTINT_14 (0x00000001 << 15)
+#define MSI_INT_EXTINT_15 (0x00000001 << 16)
+#define MSI_INT_I2CINT_0 (0x00000001 << 17)
+#define MSI_INT_I2CINT_1 (0x00000001 << 18)
+
+#define MSI_INT_STATUS_CLR_L 0xfc8
+#define MSI_INT_STATUS_CLR_H 0xfcc
+#define MSI_INT_STATUS_SET_L 0xfd0
+#define MSI_INT_STATUS_SET_H 0xfd4
+#define MSI_INT_ENA_L 0xfd8
+#define MSI_INT_ENA_H 0xfdc
+#define MSI_INT_ENA_CLR_L 0xfe0
+#define MSI_INT_ENA_CLR_H 0xfe4
+#define MSI_INT_ENA_SET_L 0xfe8
+#define MSI_INT_ENA_SET_H 0xfec
+
+#define MSI_SW_RST 0xff0
+#define MSI_SW_RESET (0x0001 << 0)
+
+#define MSI_MODULE_ID 0xffc
+
+
+/* -------------- I2C Registers -------------- */
+
+#define I2C_B 0x0000b000
+#define I2C_A 0x0000c000
+
+#define RX_FIFO 0x000
+#define I2C_RX_BYTE (0x000000ff << 0)
+
+#define TX_FIFO 0x000
+#define I2C_STOP_BIT (0x00000001 << 9)
+#define I2C_START_BIT (0x00000001 << 8)
+#define I2C_TX_BYTE (0x000000ff << 0)
+
+#define I2C_STATUS 0x008
+#define I2C_TRANSMIT (0x00000001 << 11)
+#define I2C_RECEIVE (0x00000001 << 10)
+#define I2C_TRANSMIT_S_PROG (0x00000001 << 9)
+#define I2C_TRANSMIT_S_CLEAR (0x00000001 << 8)
+#define I2C_TRANSMIT_PROG (0x00000001 << 7)
+#define I2C_TRANSMIT_CLEAR (0x00000001 << 6)
+#define I2C_RECEIVE_PROG (0x00000001 << 5)
+#define I2C_RECEIVE_CLEAR (0x00000001 << 4)
+#define I2C_SDA_LINE (0x00000001 << 3)
+#define I2C_SCL_LINE (0x00000001 << 2)
+#define I2C_START_STOP_FLAG (0x00000001 << 1)
+#define I2C_MODE_STATUS (0x00000001 << 0)
+
+#define I2C_CONTROL 0x00c
+#define I2C_SCL_CONTROL (0x00000001 << 7)
+#define I2C_SDA_CONTROL (0x00000001 << 6)
+#define I2C_RECEIVE_PROTECT (0x00000001 << 5)
+#define I2C_RECEIVE_PRO_READ (0x00000001 << 4)
+#define I2C_TRANS_SELF_CLEAR (0x00000001 << 3)
+#define I2C_TRANS_S_SELF_CLEAR (0x00000001 << 2)
+#define I2C_SLAVE_ADDR_10BIT (0x00000001 << 1)
+#define I2C_RESET (0x00000001 << 0)
+
+#define I2C_CLOCK_DIVISOR_HIGH 0x010
+#define I2C_CLOCK_HIGH (0x0000ffff << 0)
+
+#define I2C_CLOCK_DIVISOR_LOW 0x014
+#define I2C_CLOCK_LOW (0x0000ffff << 0)
+
+#define I2C_RX_LEVEL 0x01c
+#define I2C_RECEIVE_RANGE (0x0000007f << 0)
+
+#define I2C_TX_LEVEL 0x020
+#define I2C_TRANSMIT_RANGE (0x0000007f << 0)
+
+#define I2C_SDA_HOLD 0x028
+#define I2C_HOLD_TIME (0x0000007f << 0)
+
+#define MODULE_CONF 0xfd4
+#define INT_CLR_ENABLE 0xfd8
+#define I2C_CLR_ENABLE_STFNF (0x00000001 << 12)
+#define I2C_CLR_ENABLE_MTFNF (0x00000001 << 11)
+#define I2C_CLR_ENABLE_RFDA (0x00000001 << 10)
+#define I2C_CLR_ENABLE_RFF (0x00000001 << 9)
+#define I2C_CLR_ENABLE_STDR (0x00000001 << 8)
+#define I2C_CLR_ENABLE_MTDR (0x00000001 << 7)
+#define I2C_CLR_ENABLE_IBE (0x00000001 << 6)
+#define I2C_CLR_ENABLE_MSMC (0x00000001 << 5)
+#define I2C_CLR_ENABLE_SRSD (0x00000001 << 4)
+#define I2C_CLR_ENABLE_STSD (0x00000001 << 3)
+#define I2C_CLR_ENABLE_MTNA (0x00000001 << 2)
+#define I2C_CLR_ENABLE_MAF (0x00000001 << 1)
+#define I2C_CLR_ENABLE_MTD (0x00000001 << 0)
+
+#define INT_SET_ENABLE 0xfdc
+#define I2C_SET_ENABLE_STFNF (0x00000001 << 12)
+#define I2C_SET_ENABLE_MTFNF (0x00000001 << 11)
+#define I2C_SET_ENABLE_RFDA (0x00000001 << 10)
+#define I2C_SET_ENABLE_RFF (0x00000001 << 9)
+#define I2C_SET_ENABLE_STDR (0x00000001 << 8)
+#define I2C_SET_ENABLE_MTDR (0x00000001 << 7)
+#define I2C_SET_ENABLE_IBE (0x00000001 << 6)
+#define I2C_SET_ENABLE_MSMC (0x00000001 << 5)
+#define I2C_SET_ENABLE_SRSD (0x00000001 << 4)
+#define I2C_SET_ENABLE_STSD (0x00000001 << 3)
+#define I2C_SET_ENABLE_MTNA (0x00000001 << 2)
+#define I2C_SET_ENABLE_MAF (0x00000001 << 1)
+#define I2C_SET_ENABLE_MTD (0x00000001 << 0)
+
+#define INT_STATUS 0xfe0
+#define I2C_INTERRUPT_STFNF (0x00000001 << 12)
+#define I2C_INTERRUPT_MTFNF (0x00000001 << 11)
+#define I2C_INTERRUPT_RFDA (0x00000001 << 10)
+#define I2C_INTERRUPTE_RFF (0x00000001 << 9)
+#define I2C_SLAVE_INTERRUPT_STDR (0x00000001 << 8)
+#define I2C_MASTER_INTERRUPT_MTDR (0x00000001 << 7)
+#define I2C_ERROR_IBE (0x00000001 << 6)
+#define I2C_MODE_CHANGE_INTER_MSMC (0x00000001 << 5)
+#define I2C_SLAVE_RECEIVE_INTER_SRSD (0x00000001 << 4)
+#define I2C_SLAVE_TRANSMIT_INTER_STSD (0x00000001 << 3)
+#define I2C_ACK_INTER_MTNA (0x00000001 << 2)
+#define I2C_FAILURE_INTER_MAF (0x00000001 << 1)
+#define I2C_INTERRUPT_MTD (0x00000001 << 0)
+
+#define INT_ENABLE 0xfe4
+#define I2C_ENABLE_STFNF (0x00000001 << 12)
+#define I2C_ENABLE_MTFNF (0x00000001 << 11)
+#define I2C_ENABLE_RFDA (0x00000001 << 10)
+#define I2C_ENABLE_RFF (0x00000001 << 9)
+#define I2C_ENABLE_STDR (0x00000001 << 8)
+#define I2C_ENABLE_MTDR (0x00000001 << 7)
+#define I2C_ENABLE_IBE (0x00000001 << 6)
+#define I2C_ENABLE_MSMC (0x00000001 << 5)
+#define I2C_ENABLE_SRSD (0x00000001 << 4)
+#define I2C_ENABLE_STSD (0x00000001 << 3)
+#define I2C_ENABLE_MTNA (0x00000001 << 2)
+#define I2C_ENABLE_MAF (0x00000001 << 1)
+#define I2C_ENABLE_MTD (0x00000001 << 0)
+
+#define INT_CLR_STATUS 0xfe8
+#define I2C_CLR_STATUS_STFNF (0x00000001 << 12)
+#define I2C_CLR_STATUS_MTFNF (0x00000001 << 11)
+#define I2C_CLR_STATUS_RFDA (0x00000001 << 10)
+#define I2C_CLR_STATUS_RFF (0x00000001 << 9)
+#define I2C_CLR_STATUS_STDR (0x00000001 << 8)
+#define I2C_CLR_STATUS_MTDR (0x00000001 << 7)
+#define I2C_CLR_STATUS_IBE (0x00000001 << 6)
+#define I2C_CLR_STATUS_MSMC (0x00000001 << 5)
+#define I2C_CLR_STATUS_SRSD (0x00000001 << 4)
+#define I2C_CLR_STATUS_STSD (0x00000001 << 3)
+#define I2C_CLR_STATUS_MTNA (0x00000001 << 2)
+#define I2C_CLR_STATUS_MAF (0x00000001 << 1)
+#define I2C_CLR_STATIS_MTD (0x00000001 << 0)
+
+#define INT_SET_STATUS 0xfec
+#define I2C_SET_STATUS_STFNF (0x00000001 << 12)
+#define I2C_SET_STATUS_MTFNF (0x00000001 << 11)
+#define I2C_SET_STATUS_RFDA (0x00000001 << 10)
+#define I2C_SET_STATUS_RFF (0x00000001 << 9)
+#define I2C_SET_STATUS_STDR (0x00000001 << 8)
+#define I2C_SET_STATUS_MTDR (0x00000001 << 7)
+#define I2C_SET_STATUS_IBE (0x00000001 << 6)
+#define I2C_SET_STATUS_MSMC (0x00000001 << 5)
+#define I2C_SET_STATUS_SRSD (0x00000001 << 4)
+#define I2C_SET_STATUS_STSD (0x00000001 << 3)
+#define I2C_SET_STATUS_MTNA (0x00000001 << 2)
+#define I2C_SET_STATUS_MAF (0x00000001 << 1)
+#define I2C_SET_STATIS_MTD (0x00000001 << 0)
+
+
+
+
+/* -------------- SPI Registers -------------- */
+
+#define SPI 0x0000d000
+
+#define SPI_CONTROL_REG 0x000
+#define SPI_SERIAL_INTER_ENABLE (0x00000001 << 7)
+#define SPI_LSB_FIRST_ENABLE (0x00000001 << 6)
+#define SPI_MODE_SELECT (0x00000001 << 5)
+#define SPI_CLOCK_POLARITY (0x00000001 << 4)
+#define SPI_CLOCK_PHASE (0x00000001 << 3)
+
+#define SPI_STATUS 0x004
+#define SPI_TRANSFER_FLAG (0x00000001 << 7)
+#define SPI_WRITE_COLLISSION (0x00000001 << 6)
+#define SPI_READ_OVERRUN (0x00000001 << 5)
+#define SPI_MODE_FAULT (0x00000001 << 4)
+#define SPI_SLAVE_ABORT (0x00000001 << 3)
+
+#define SPI_DATA 0x008
+#define SPI_BIDI_DATA (0x000000ff << 0)
+
+#define SPI_CLOCK_COUNTER 0x00c
+#define SPI_CLOCK (0x00000001 << 0)
+
+
+
+
+/* -------------- GPIO Registers -------------- */
+
+#define GPIO 0x0000e000
+
+#define GPIO_RD 0x000
+#define GPIO_WR 0x004
+#define GPIO_WR_MODE 0x008
+#define GPIO_OEN 0x00c
+
+#define GPIO_SW_RST 0xff0
+#define GPIO_SW_RESET (0x00000001 << 0)
+
+#define GPIO_31 (1 << 31)
+#define GPIO_30 (1 << 30)
+#define GPIO_29 (1 << 29)
+#define GPIO_28 (1 << 28)
+#define GPIO_27 (1 << 27)
+#define GPIO_26 (1 << 26)
+#define GPIO_25 (1 << 25)
+#define GPIO_24 (1 << 24)
+#define GPIO_23 (1 << 23)
+#define GPIO_22 (1 << 22)
+#define GPIO_21 (1 << 21)
+#define GPIO_20 (1 << 20)
+#define GPIO_19 (1 << 19)
+#define GPIO_18 (1 << 18)
+#define GPIO_17 (1 << 17)
+#define GPIO_16 (1 << 16)
+#define GPIO_15 (1 << 15)
+#define GPIO_14 (1 << 14)
+#define GPIO_13 (1 << 13)
+#define GPIO_12 (1 << 12)
+#define GPIO_11 (1 << 11)
+#define GPIO_10 (1 << 10)
+#define GPIO_09 (1 << 9)
+#define GPIO_08 (1 << 8)
+#define GPIO_07 (1 << 7)
+#define GPIO_06 (1 << 6)
+#define GPIO_05 (1 << 5)
+#define GPIO_04 (1 << 4)
+#define GPIO_03 (1 << 3)
+#define GPIO_02 (1 << 2)
+#define GPIO_01 (1 << 1)
+#define GPIO_00 (1 << 0)
+
+/* -------------- PHI_0 Registers -------------- */
+
+#define PHI_0 0x0000f000
+
+#define PHI_0_MODE 0x0000
+#define PHI_0_0_CONFIG 0x0008
+#define PHI_0_1_CONFIG 0x000c
+#define PHI_0_2_CONFIG 0x0010
+#define PHI_0_3_CONFIG 0x0014
+
+#define PHI_POLARITY 0x0038
+#define PHI_TIMEOUT 0x003c
+#define PHI_SW_RST 0x0ff0
+
+#define PHI_0_0_RW_0 0x1000
+#define PHI_0_0_RW_511 0x17fc
+
+#define PHI_0_1_RW_0 0x1800
+#define PHI_0_1_RW_511 0x1ffc
+
+#define PHI_0_2_RW_0 0x2000
+#define PHI_0_2_RW_511 0x27fc
+
+#define PHI_0_3_RW_0 0x2800
+#define PHI_0_3_RW_511 0x2ffc
+
+#define PHI_CSN_DEASSERT (0x00000001 << 2)
+#define PHI_AUTO_INCREMENT (0x00000001 << 1)
+#define PHI_FIFO_MODE (0x00000001 << 0)
+
+#define PHI_DELAY_RD_WR (0x0000001f << 27)
+#define PHI_EXTEND_RDY3 (0x00000003 << 25)
+#define PHI_EXTEND_RDY2 (0x00000003 << 23)
+#define PHI_EXTEND_RDY1 (0x00000003 << 21)
+#define PHI_EXTEND_RDY0 (0x00000003 << 19)
+#define PHI_RDY3_OD (0x00000001 << 18)
+#define PHI_RDY2_OD (0x00000001 << 17)
+#define PHI_RDY1_OD (0x00000001 << 16)
+#define PHI_RDY0_OD (0x00000001 << 15)
+#define PHI_ALE_POL (0x00000001 << 14)
+#define PHI_WRN_POL (0x00000001 << 13)
+#define PHI_RDN_POL (0x00000001 << 12)
+#define PHI_RDY3_POL (0x00000001 << 11)
+#define PHI_RDY2_POL (0x00000001 << 10)
+#define PHI_RDY1_POL (0x00000001 << 9)
+#define PHI_RDY0_POL (0x00000001 << 8)
+#define PHI_CSN7_POL (0x00000001 << 7)
+#define PHI_CSN6_POL (0x00000001 << 6)
+#define PHI_CSN5_POL (0x00000001 << 5)
+#define PHI_CSN4_POL (0x00000001 << 4)
+#define PHI_CSN3_POL (0x00000001 << 3)
+#define PHI_CSN2_POL (0x00000001 << 2)
+#define PHI_CSN1_POL (0x00000001 << 1)
+#define PHI_CSN0_POL (0x00000001 << 0)
+
+/* -------------- PHI_1 Registers -------------- */
+
+#define PHI_1 0x00020000
+
+#define PHI_1_MODE 0x00004
+#define PHI_1_0_CONFIG 0x00018
+#define PHI_1_1_CONFIG 0x0001c
+#define PHI_1_2_CONFIG 0x00020
+#define PHI_1_3_CONFIG 0x00024
+#define PHI_1_4_CONFIG 0x00028
+#define PHI_1_5_CONFIG 0x0002c
+#define PHI_1_6_CONFIG 0x00030
+#define PHI_1_7_CONFIG 0x00034
+
+#define PHI_1_0_RW_0 0x00000
+#define PHI_1_0_RW_16383 0x0fffc
+
+#define PHI_1_1_RW_0 0x1000
+#define PHI_1_1_RW_16383 0x1ffc
+
+#define PHI_1_2_RW_0 0x2000
+#define PHI_1_2_RW_16383 0x2ffc
+
+#define PHI_1_3_RW_0 0x3000
+#define PHI_1_3_RW_16383 0x3ffc
+
+#define PHI_1_4_RW_0 0x4000
+#define PHI_1_4_RW_16383 0x4ffc
+
+#define PHI_1_5_RW_0 0x5000
+#define PHI_1_5_RW_16383 0x5ffc
+
+#define PHI_1_6_RW_0 0x6000
+#define PHI_1_6_RW_16383 0x6ffc
+
+#define PHI_1_7_RW_0 0x7000
+#define PHI_1_7_RW_16383 0x7ffc
+
+/* -------------- CGU Registers -------------- */
+
+#define CGU 0x00013000
+
+#define CGU_SCR_0 0x000
+#define CGU_SCR_1 0x004
+#define CGU_SCR_2 0x008
+#define CGU_SCR_3 0x00c
+#define CGU_SCR_4 0x010
+#define CGU_SCR_5 0x014
+#define CGU_SCR_6 0x018
+#define CGU_SCR_7 0x01c
+#define CGU_SCR_8 0x020
+#define CGU_SCR_9 0x024
+#define CGU_SCR_10 0x028
+#define CGU_SCR_11 0x02c
+#define CGU_SCR_12 0x030
+#define CGU_SCR_13 0x034
+#define CGU_SCR_STOP (0x00000001 << 3)
+#define CGU_SCR_RESET (0x00000001 << 2)
+#define CGU_SCR_ENF2 (0x00000001 << 1)
+#define CGU_SCR_ENF1 (0x00000001 << 0)
+
+#define CGU_FS1_0 0x038
+#define CGU_FS1_1 0x03c
+#define CGU_FS1_2 0x040
+#define CGU_FS1_3 0x044
+#define CGU_FS1_4 0x048
+#define CGU_FS1_5 0x04c
+#define CGU_FS1_6 0x050
+#define CGU_FS1_7 0x054
+#define CGU_FS1_8 0x058
+#define CGU_FS1_9 0x05c
+#define CGU_FS1_10 0x060
+#define CGU_FS1_11 0x064
+#define CGU_FS1_12 0x068
+#define CGU_FS1_13 0x06c
+#define CGU_FS1_PLL (0x00000000 << 0)
+
+
+#define CGU_FS2_0 0x070
+#define CGU_FS2_1 0x074
+#define CGU_FS2_2 0x078
+#define CGU_FS2_3 0x07c
+#define CGU_FS2_4 0x080
+#define CGU_FS2_5 0x084
+#define CGU_FS2_6 0x088
+#define CGU_FS2_7 0x08c
+#define CGU_FS2_8 0x090
+#define CGU_FS2_9 0x094
+#define CGU_FS2_10 0x098
+#define CGU_FS2_11 0x09c
+#define CGU_FS2_12 0x0a0
+#define CGU_FS2_13 0x0a4
+
+#define CGU_SSR_0 0x0a8
+#define CGU_SSR_1 0x0ac
+#define CGU_SSR_2 0x0b0
+#define CGU_SSR_3 0x0b4
+#define CGU_SSR_4 0x0b8
+#define CGU_SSR_5 0x0bc
+#define CGU_SSR_6 0x0c0
+#define CGU_SSR_7 0x0c4
+#define CGU_SSR_8 0x0c8
+#define CGU_SSR_9 0x0cc
+#define CGU_SSR_10 0x0d0
+#define CGU_SSR_11 0x0d4
+#define CGU_SSR_12 0x0d8
+#define CGU_SSR_13 0x0dc
+
+#define CGU_PCR_0_0 0x0e0
+#define CGU_PCR_0_1 0x0e4
+#define CGU_PCR_0_2 0x0e8
+#define CGU_PCR_0_3 0x0ec
+#define CGU_PCR_0_4 0x0f0
+#define CGU_PCR_0_5 0x0f4
+#define CGU_PCR_0_6 0x0f8
+#define CGU_PCR_0_7 0x0fc
+#define CGU_PCR_1_0 0x100
+#define CGU_PCR_1_1 0x104
+#define CGU_PCR_2_0 0x108
+#define CGU_PCR_2_1 0x10c
+#define CGU_PCR_3_0 0x110
+#define CGU_PCR_3_1 0x114
+#define CGU_PCR_3_2 0x118
+#define CGU_PCR_4_0 0x11c
+#define CGU_PCR_4_1 0x120
+#define CGU_PCR_5 0x124
+#define CGU_PCR_6 0x128
+#define CGU_PCR_7 0x12c
+#define CGU_PCR_8 0x130
+#define CGU_PCR_9 0x134
+#define CGU_PCR_10 0x138
+#define CGU_PCR_11 0x13c
+#define CGU_PCR_12 0x140
+#define CGU_PCR_13 0x144
+#define CGU_PCR_WAKE_EN (0x00000001 << 2)
+#define CGU_PCR_AUTO (0x00000001 << 1)
+#define CGU_PCR_RUN (0x00000001 << 0)
+
+
+#define CGU_PSR_0_0 0x148
+#define CGU_PSR_0_1 0x14c
+#define CGU_PSR_0_2 0x150
+#define CGU_PSR_0_3 0x154
+#define CGU_PSR_0_4 0x158
+#define CGU_PSR_0_5 0x15c
+#define CGU_PSR_0_6 0x160
+#define CGU_PSR_0_7 0x164
+#define CGU_PSR_1_0 0x168
+#define CGU_PSR_1_1 0x16c
+#define CGU_PSR_2_0 0x170
+#define CGU_PSR_2_1 0x174
+#define CGU_PSR_3_0 0x178
+#define CGU_PSR_3_1 0x17c
+#define CGU_PSR_3_2 0x180
+#define CGU_PSR_4_0 0x184
+#define CGU_PSR_4_1 0x188
+#define CGU_PSR_5 0x18c
+#define CGU_PSR_6 0x190
+#define CGU_PSR_7 0x194
+#define CGU_PSR_8 0x198
+#define CGU_PSR_9 0x19c
+#define CGU_PSR_10 0x1a0
+#define CGU_PSR_11 0x1a4
+#define CGU_PSR_12 0x1a8
+#define CGU_PSR_13 0x1ac
+
+#define CGU_ESR_0_0 0x1b0
+#define CGU_ESR_0_1 0x1b4
+#define CGU_ESR_0_2 0x1b8
+#define CGU_ESR_0_3 0x1bc
+#define CGU_ESR_0_4 0x1c0
+#define CGU_ESR_0_5 0x1c4
+#define CGU_ESR_0_6 0x1c8
+#define CGU_ESR_0_7 0x1cc
+#define CGU_ESR_1_0 0x1d0
+#define CGU_ESR_1_1 0x1d4
+#define CGU_ESR_2_0 0x1d8
+#define CGU_ESR_2_1 0x1dc
+#define CGU_ESR_3_0 0x1e0
+#define CGU_ESR_3_1 0x1e4
+#define CGU_ESR_3_2 0x1e8
+#define CGU_ESR_4_0 0x1ec
+#define CGU_ESR_4_1 0x1f0
+#define CGU_ESR_5 0x1f4
+#define CGU_ESR_6 0x1f8
+#define CGU_ESR_7 0x1fc
+#define CGU_ESR_8 0x200
+#define CGU_ESR_9 0x204
+#define CGU_ESR_10 0x208
+#define CGU_ESR_11 0x20c
+#define CGU_ESR_12 0x210
+#define CGU_ESR_13 0x214
+#define CGU_ESR_FD_EN (0x00000001 << 0)
+
+#define CGU_FDC_0 0x218
+#define CGU_FDC_1 0x21c
+#define CGU_FDC_2 0x220
+#define CGU_FDC_3 0x224
+#define CGU_FDC_4 0x228
+#define CGU_FDC_5 0x22c
+#define CGU_FDC_6 0x230
+#define CGU_FDC_7 0x234
+#define CGU_FDC_8 0x238
+#define CGU_FDC_9 0x23c
+#define CGU_FDC_10 0x240
+#define CGU_FDC_11 0x244
+#define CGU_FDC_12 0x248
+#define CGU_FDC_13 0x24c
+#define CGU_FDC_STRETCH (0x00000001 << 0)
+#define CGU_FDC_RESET (0x00000001 << 1)
+#define CGU_FDC_RUN1 (0x00000001 << 2)
+#define CGU_FDC_MADD (0x000000ff << 3)
+#define CGU_FDC_MSUB (0x000000ff << 11)
+
+/* -------------- DCS Registers -------------- */
+
+#define DCS 0x00014000
+
+#define DCSC_CTRL 0x000
+#define DCSC_SEL_PLLDI (0x03ffffff << 5)
+#define DCSC_TOUT_SEL (0x0000000f << 1)
+#define DCSC_TOUT_OFF (0x00000001 << 0)
+
+#define DCSC_ADDR 0x00c
+#define DCSC_ERR_TOUT_ADDR (0x3fffffff << 2)
+
+#define DCSC_STAT 0x010
+#define DCSC_ERR_TOUT_GNT (0x0000001f << 24)
+#define DCSC_ERR_TOUT_SEL (0x0000007f << 10)
+#define DCSC_ERR_TOUT_READ (0x00000001 << 8)
+#define DCSC_ERR_TOUT_MASK (0x0000000f << 4)
+#define DCSC_ERR_ACK (0x00000001 << 1)
+
+#define DCSC_FEATURES 0x040
+#define DCSC_UNIQUE_ID (0x00000007 << 16)
+#define DCSC_SECURITY (0x00000001 << 14)
+#define DCSC_NUM_BASE_REGS (0x00000003 << 11)
+#define DCSC_NUM_TARGETS (0x0000001f << 5)
+#define DCSC_NUM_INITIATORS (0x0000001f << 0)
+
+#define DCSC_BASE_REG0 0x100
+#define DCSC_BASE_N_REG (0x00000fff << 20)
+
+#define DCSC_INT_CLR_ENABLE 0xfd8
+#define DCSC_INT_CLR_ENABLE_TOUT (0x00000001 << 1)
+#define DCSC_INT_CLR_ENABLE_ERROR (0x00000001 << 0)
+
+#define DCSC_INT_SET_ENABLE 0xfdc
+#define DCSC_INT_SET_ENABLE_TOUT (0x00000001 << 1)
+#define DCSC_INT_SET_ENABLE_ERROR (0x00000001 << 0)
+
+#define DCSC_INT_STATUS 0xfe0
+#define DCSC_INT_STATUS_TOUT (0x00000001 << 1)
+#define DCSC_INT_STATUS_ERROR (0x00000001 << 0)
+
+#define DCSC_INT_ENABLE 0xfe4
+#define DCSC_INT_ENABLE_TOUT (0x00000001 << 1)
+#define DCSC_INT_ENABLE_ERROR (0x00000001 << 0)
+
+#define DCSC_INT_CLR_STATUS 0xfe8
+#define DCSC_INT_CLEAR_TOUT (0x00000001 << 1)
+#define DCSC_INT_CLEAR_ERROR (0x00000001 << 0)
+
+#define DCSC_INT_SET_STATUS 0xfec
+#define DCSC_INT_SET_TOUT (0x00000001 << 1)
+#define DCSC_INT_SET_ERROR (0x00000001 << 0)
+
+
+
+
+/* -------------- GREG Registers -------------- */
+
+#define GREG 0x00012000
+
+#define GREG_SUBSYS_CONFIG 0x000
+#define GREG_SUBSYS_ID (0x0000ffff << 16)
+#define GREG_SUBSYS_VID (0x0000ffff << 0)
+
+#define GREG_MSI_BAR_PMCSR 0x004
+#define GREG_PMCSR_SCALE_7 (0x00000003 << 30)
+#define GREG_PMCSR_SCALE_6 (0x00000003 << 28)
+#define GREG_PMCSR_SCALE_5 (0x00000003 << 26)
+#define GREG_PMCSR_SCALE_4 (0x00000003 << 24)
+#define GREG_PMCSR_SCALE_3 (0x00000003 << 22)
+#define GREG_PMCSR_SCALE_2 (0x00000003 << 20)
+#define GREG_PMCSR_SCALE_1 (0x00000003 << 18)
+#define GREG_PMCSR_SCALE_0 (0x00000003 << 16)
+
+#define GREG_BAR_WIDTH_17 (0x0000001e << 8)
+#define GREG_BAR_WIDTH_18 (0x0000001c << 8)
+#define GREG_BAR_WIDTH_19 (0x00000018 << 8)
+#define GREG_BAR_WIDTH_20 (0x00000010 << 8)
+
+#define GREG_BAR_PREFETCH (0x00000001 << 3)
+#define GREG_MSI_MM_CAP1 (0x00000000 << 0) // FIXME !
+#define GREG_MSI_MM_CAP2 (0x00000001 << 0)
+#define GREG_MSI_MM_CAP4 (0x00000002 << 0)
+#define GREG_MSI_MM_CAP8 (0x00000003 << 0)
+#define GREG_MSI_MM_CAP16 (0x00000004 << 0)
+#define GREG_MSI_MM_CAP32 (0x00000005 << 0)
+
+#define GREG_PMCSR_DATA_1 0x008
+#define GREG_PMCSR_DATA_2 0x00c
+#define GREG_VI_CTRL 0x010
+#define GREG_FGPI_CTRL 0x014
+
+#define GREG_RSTU_CTRL 0x018
+#define GREG_BOOT_READY (0x00000001 << 13)
+#define GREG_RESET_REQ (0x00000001 << 12)
+#define GREG_IP_RST_RELEASE (0x00000001 << 11)
+#define GREG_ADAPTER_RST_RELEASE (0x00000001 << 10)
+#define GREG_PCIE_CORE_RST_RELEASE (0x00000001 << 9)
+#define GREG_BOOT_IP_RST_RELEASE (0x00000001 << 8)
+#define GREG_BOOT_RST_RELEASE (0x00000001 << 7)
+#define GREG_CGU_RST_RELEASE (0x00000001 << 6)
+#define GREG_IP_RST_ASSERT (0x00000001 << 5)
+#define GREG_ADAPTER_RST_ASSERT (0x00000001 << 4)
+#define GREG_RST_ASSERT (0x00000001 << 3)
+#define GREG_BOOT_IP_RST_ASSERT (0x00000001 << 2)
+#define GREG_BOOT_RST_ASSERT (0x00000001 << 1)
+#define GREG_CGU_RST_ASSERT (0x00000001 << 0)
+
+#define GREG_I2C_CTRL 0x01c
+#define GREG_I2C_SLAVE_ADDR (0x0000007f << 0)
+
+#define GREG_OVFLW_CTRL 0x020
+#define GREG_OVERFLOW_ENABLE (0x00001fff << 0)
+
+#define GREG_TAG_ACK_FLEN 0x024
+#define GREG_TAG_ACK_FLEN_1B (0x00000000 << 0)
+#define GREG_TAG_ACK_FLEN_2B (0x00000001 << 0)
+#define GREG_TAG_ACK_FLEN_4B (0x00000002 << 0)
+#define GREG_TAG_ACK_FLEN_8B (0x00000003 << 0)
+
+#define GREG_VIDEO_IN_CTRL 0x028
+
+#define GREG_SPARE_1 0x02c
+#define GREG_SPARE_2 0x030
+#define GREG_SPARE_3 0x034
+#define GREG_SPARE_4 0x038
+#define GREG_SPARE_5 0x03c
+#define GREG_SPARE_6 0x040
+#define GREG_SPARE_7 0x044
+#define GREG_SPARE_8 0x048
+#define GREG_SPARE_9 0x04c
+#define GREG_SPARE_10 0x050
+#define GREG_SPARE_11 0x054
+#define GREG_SPARE_12 0x058
+#define GREG_SPARE_13 0x05c
+#define GREG_SPARE_14 0x060
+#define GREG_SPARE_15 0x064
+
+#define GREG_FAIL_DISABLE 0x068
+#define GREG_BOOT_FAIL_DISABLE (0x00000001 << 0)
+
+#define GREG_SW_RST 0xff0
+#define GREG_SW_RESET (0x00000001 << 0)
+
+
+
+
+/* BAR = 20 bits */
+
+/* -------------- PHI1 Registers -------------- */
+
+#define PHI_1 0x00020000
+
+
+
+#endif /* __SAA716x_REG_H */
diff --git a/drivers/media/common/saa716x/saa716x_rom.c b/drivers/media/common/saa716x/saa716x_rom.c
new file mode 100644
index 0000000..7f8dbe1
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_rom.c
@@ -0,0 +1,1071 @@
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include "saa716x_rom.h"
+#include "saa716x_adap.h"
+#include "saa716x_spi.h"
+#include "saa716x_priv.h"
+
+int i;
+
+static int eeprom_read_bytes(struct saa716x_dev *saa716x, u16 reg, u16 len, u8 *val)
+{
+ struct saa716x_i2c *i2c = saa716x->i2c;
+ struct i2c_adapter *adapter = &i2c[SAA716x_I2C_BUS_B].i2c_adapter;
+
+ u8 b0[] = { MSB(reg), LSB(reg) };
+ int ret;
+
+ struct i2c_msg msg[] = {
+ { .addr = 0x50, .flags = 0, .buf = b0, .len = sizeof (b0) },
+ { .addr = 0x50, .flags = I2C_M_RD, .buf = val, .len = len }
+ };
+
+ ret = i2c_transfer(adapter, msg, 2);
+ if (ret != 2) {
+ dprintk(SAA716x_ERROR, 1, "read error <reg=0x%02x, ret=%i>", reg, ret);
+ return -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+static int saa716x_read_rombytes(struct saa716x_dev *saa716x, u16 reg, u16 len, u8 *val)
+{
+ struct saa716x_i2c *i2c = saa716x->i2c;
+ struct i2c_adapter *adapter = &i2c[SAA716x_I2C_BUS_B].i2c_adapter;
+ struct i2c_msg msg[2];
+
+ u8 b0[2];
+ int ret, count;
+
+ count = len / DUMP_BYTES;
+ if (len % DUMP_BYTES)
+ count++;
+
+ count *= 2;
+
+ for (i = 0; i < count; i += 2) {
+ dprintk(SAA716x_DEBUG, 1, "Length=%d, Count=%d, Reg=0x%02x",
+ len,
+ count,
+ reg);
+
+ b0[0] = MSB(reg);
+ b0[1] = LSB(reg);
+
+ /* Write */
+ msg[0].addr = 0x50;
+ msg[0].flags = 0;
+ msg[0].buf = b0;
+ msg[0].len = 2;
+
+ /* Read */
+ msg[1].addr = 0x50;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = val;
+
+ if (i == (count - 2)) {
+ /* last message */
+ if (len % DUMP_BYTES) {
+ msg[1].len = len % DUMP_BYTES;
+ dprintk(SAA716x_DEBUG, 1, "Last Message length=%d", len % DUMP_BYTES);
+ } else {
+ msg[1].len = DUMP_BYTES;
+ }
+ } else {
+ msg[1].len = DUMP_BYTES;
+ }
+
+ ret = i2c_transfer(adapter, msg, 2);
+ if (ret != 2) {
+ dprintk(SAA716x_ERROR, 1, "read error <reg=0x%02x, ret=%i>", reg, ret);
+ return -EREMOTEIO;
+ }
+
+ reg += DUMP_BYTES;
+ val += DUMP_BYTES;
+ }
+
+ return 0;
+}
+
+static int saa716x_get_offset(struct saa716x_dev *saa716x, u8 *buf, u32 *offset)
+{
+ int i;
+
+ *offset = 0;
+ for (i = 0; i < 256; i++) {
+ if (!(strncmp("START", buf + i, 5)))
+ break;
+ }
+ dprintk(SAA716x_INFO, 1, "Offset @ %d", i);
+ *offset = i;
+
+ return 0;
+}
+
+static int saa716x_eeprom_header(struct saa716x_dev *saa716x,
+ struct saa716x_romhdr *rom_header,
+ u8 *buf,
+ u32 *offset)
+{
+ memcpy(rom_header, &buf[*offset], sizeof (struct saa716x_romhdr));
+ if (rom_header->header_size != sizeof (struct saa716x_romhdr)) {
+ dprintk(SAA716x_ERROR, 1,
+ "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d",
+ (int)sizeof (struct saa716x_romhdr),
+ rom_header->header_size);
+
+ return -1;
+ }
+ *offset += sizeof (struct saa716x_romhdr);
+
+ dprintk(SAA716x_NOTICE, 0, "SAA%02x ROM: Data=%d bytes\n",
+ saa716x->pdev->device,
+ rom_header->data_size);
+
+ dprintk(SAA716x_NOTICE, 0, "SAA%02x ROM: Version=%d\n",
+ saa716x->pdev->device,
+ rom_header->version);
+
+ dprintk(SAA716x_NOTICE, 0, "SAA%02x ROM: Devices=%d\n",
+ saa716x->pdev->device,
+ rom_header->devices);
+
+ dprintk(SAA716x_NOTICE, 0, "SAA%02x ROM: Compressed=%d\n\n",
+ saa716x->pdev->device,
+ rom_header->compression);
+
+ return 0;
+}
+
+int saa716x_dump_eeprom(struct saa716x_dev *saa716x)
+{
+ struct saa716x_romhdr rom_header;
+ u8 buf[DUMP_BYTES];
+ int i, err = 0;
+ u32 offset = 0;
+
+ err = eeprom_read_bytes(saa716x, DUMP_OFFST, DUMP_BYTES, buf);
+ if (err < 0) {
+ dprintk(SAA716x_ERROR, 1, "EEPROM Read error");
+ return err;
+ }
+
+ dprintk(SAA716x_NOTICE, 0, " Card: %s\n",
+ saa716x->config->model_name);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " ---------------- SAA%02x ROM @ Offset 0x%02x ----------------",
+ saa716x->pdev->device,
+ DUMP_OFFST);
+
+ for (i = 0; i < DUMP_BYTES; i++) {
+ if ((i % 16) == 0) {
+ dprintk(SAA716x_NOTICE, 0, "\n ");
+ dprintk(SAA716x_NOTICE, 0, "%04x: ", i);
+ }
+
+ if ((i % 8) == 0)
+ dprintk(SAA716x_NOTICE, 0, " ");
+ if ((i % 4) == 0)
+ dprintk(SAA716x_NOTICE, 0, " ");
+ dprintk(SAA716x_NOTICE, 0, "%02x ", buf[i]);
+ }
+ dprintk(SAA716x_NOTICE, 0, "\n");
+ dprintk(SAA716x_NOTICE, 0,
+ " ---------------- SAA%02x ROM Dump end ---------------------\n\n",
+ saa716x->pdev->device);
+
+ err = saa716x_get_offset(saa716x, buf, &offset);
+ if (err != 0) {
+ dprintk(SAA716x_ERROR, 1, "ERROR: Descriptor not found <%d>", err);
+ return err;
+ }
+ offset += 5;
+ saa716x->id_offst = offset;
+ /* Get header */
+ err = saa716x_eeprom_header(saa716x, &rom_header, buf, &offset);
+ if (err != 0) {
+ dprintk(SAA716x_ERROR, 1, "ERROR: Header Read failed <%d>", err);
+ return -1;
+ }
+ saa716x->id_len = rom_header.data_size;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa716x_dump_eeprom);
+
+static void saa716x_descriptor_dbg(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset,
+ u8 size,
+ u8 ext_size)
+{
+ int i;
+
+ dprintk(SAA716x_INFO, 0, " ");
+ for (i = 0; i < 49; i++)
+ dprintk(SAA716x_INFO, 0, "-");
+
+ for (i = 0; i < size + ext_size; i++) {
+ if ((i % 16) == 0)
+ dprintk(SAA716x_INFO, 0, "\n ");
+ if ((i % 8) == 0)
+ dprintk(SAA716x_INFO, 0, " ");
+ if ((i % 4) == 0)
+ dprintk(SAA716x_INFO, 0, " ");
+
+ dprintk(SAA716x_INFO, 0, "%02x ", buf[*offset + i]);
+ }
+
+ dprintk(SAA716x_INFO, 0, "\n ");
+ for (i = 0; i < 49; i++)
+ dprintk(SAA716x_INFO, 0, "-");
+ dprintk(SAA716x_INFO, 0, "\n");
+
+}
+
+static int saa716x_decoder_info(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset)
+{
+ struct saa716x_decoder_hdr header;
+
+ memcpy(&header, &buf[*offset], sizeof (struct saa716x_decoder_hdr));
+ saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data);
+ if (header.size != sizeof (struct saa716x_decoder_hdr)) {
+ dprintk(SAA716x_ERROR, 1,
+ "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d",
+ header.size,
+ (int)sizeof (struct saa716x_decoder_hdr));
+
+ return -1;
+ }
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ header.size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Ext Data=%d bytes\n\n",
+ saa716x->pdev->device,
+ header.ext_data);
+
+ *offset += header.size + header.ext_data;
+ return 0;
+}
+
+static int saa716x_gpio_info(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset)
+{
+ struct saa716x_gpio_hdr header;
+
+ memcpy(&header, &buf[*offset], sizeof (struct saa716x_gpio_hdr));
+ saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data);
+ if (header.size != sizeof (struct saa716x_gpio_hdr)) {
+ dprintk(SAA716x_ERROR, 1,
+ "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d",
+ header.size,
+ (int)sizeof (struct saa716x_gpio_hdr));
+
+ return -1;
+ }
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ header.size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Pins=%d\n",
+ saa716x->pdev->device,
+ header.pins);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Ext data=%d\n\n",
+ saa716x->pdev->device,
+ header.ext_data);
+
+ *offset += header.size + header.ext_data;
+
+ return 0;
+}
+
+static int saa716x_video_decoder_info(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset)
+{
+ struct saa716x_video_decoder_hdr header;
+
+ memcpy(&header, &buf[*offset], sizeof (struct saa716x_video_decoder_hdr));
+ saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data);
+ if (header.size != sizeof (struct saa716x_video_decoder_hdr)) {
+ dprintk(SAA716x_ERROR, 1,
+ "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d",
+ header.size,
+ (int)sizeof (struct saa716x_video_decoder_hdr));
+
+ return -1;
+ }
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ header.size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: PORT 0=0x%02x\n",
+ saa716x->pdev->device,
+ header.video_port0);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: PORT 1=0x%02x\n",
+ saa716x->pdev->device,
+ header.video_port1);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: PORT 2=0x%02x\n",
+ saa716x->pdev->device,
+ header.video_port2);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: VBI PORT ID=0x%02x\n",
+ saa716x->pdev->device,
+ header.vbi_port_id);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Video PORT Type=0x%02x\n",
+ saa716x->pdev->device,
+ header.video_port_type);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: VBI PORT Type=0x%02x\n",
+ saa716x->pdev->device,
+ header.vbi_port_type);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Encoder PORT Type=0x%02x\n",
+ saa716x->pdev->device,
+ header.encoder_port_type);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Video Output=0x%02x\n",
+ saa716x->pdev->device,
+ header.video_output);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: VBI Output=0x%02x\n",
+ saa716x->pdev->device,
+ header.vbi_output);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Encoder Output=0x%02x\n",
+ saa716x->pdev->device,
+ header.encoder_output);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Ext data=%d bytes\n\n",
+ saa716x->pdev->device,
+ header.ext_data);
+
+ *offset += header.size + header.ext_data;
+ return 0;
+}
+
+static int saa716x_audio_decoder_info(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset)
+{
+ struct saa716x_audio_decoder_hdr header;
+
+ memcpy(&header, &buf[*offset], sizeof (struct saa716x_audio_decoder_hdr));
+ saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data);
+ if (header.size != sizeof (struct saa716x_audio_decoder_hdr)) {
+ dprintk(SAA716x_ERROR, 1,
+ "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d",
+ header.size,
+ (int)sizeof (struct saa716x_audio_decoder_hdr));
+
+ return -1;
+ }
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ header.size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Ext data=%d bytes\n\n",
+ saa716x->pdev->device,
+ header.ext_data);
+
+ *offset += header.size + header.ext_data;
+ return 0;
+}
+
+static int saa716x_event_source_info(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset)
+{
+ struct saa716x_evsrc_hdr header;
+
+ memcpy(&header, &buf[*offset], sizeof (struct saa716x_evsrc_hdr));
+ saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data);
+ if (header.size != sizeof (struct saa716x_evsrc_hdr)) {
+ dprintk(SAA716x_ERROR, 1,
+ "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d",
+ header.size,
+ (int)sizeof (struct saa716x_evsrc_hdr));
+
+ return -1;
+ }
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ header.size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Ext data=%d bytes\n\n",
+ saa716x->pdev->device,
+ header.ext_data);
+
+ *offset += header.size + header.ext_data;
+ return 0;
+}
+
+static int saa716x_crossbar_info(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset)
+{
+ struct saa716x_xbar_hdr header;
+ struct saa716x_xbar_pair_info pair_info;
+
+ memcpy(&header, &buf[*offset], sizeof (struct saa716x_xbar_hdr));
+ saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data);
+ if (header.size != sizeof (struct saa716x_xbar_hdr)) {
+ dprintk(SAA716x_ERROR, 1,
+ "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d",
+ header.size,
+ (int)sizeof (struct saa716x_xbar_hdr));
+
+ return -1;
+ }
+
+ memcpy(&pair_info, &buf[*offset], sizeof (struct saa716x_xbar_pair_info));
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ header.size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Pairs=%d\n",
+ saa716x->pdev->device,
+ header.pair_inputs);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Ext data=%d bytes\n\n",
+ saa716x->pdev->device,
+ header.ext_data);
+
+ *offset += header.size + header.ext_data + (sizeof (struct saa716x_xbar_pair_info) * header.pair_inputs);
+ return 0;
+}
+
+static int saa716x_tuner_info(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset)
+{
+ struct saa716x_tuner_hdr header;
+
+ memcpy(&header, &buf[*offset], sizeof (struct saa716x_tuner_hdr));
+ saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data);
+ if (header.size != sizeof (struct saa716x_tuner_hdr)) {
+ dprintk(SAA716x_ERROR, 1,
+ "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d",
+ header.size,
+ (int)sizeof (struct saa716x_tuner_hdr));
+
+ return -1;
+ }
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ header.size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Ext data=%d bytes\n\n",
+ saa716x->pdev->device,
+ header.ext_data);
+
+ *offset += header.size + header.ext_data;
+ return 0;
+}
+
+static int saa716x_pll_info(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset)
+{
+ struct saa716x_pll_hdr header;
+
+ memcpy(&header, &buf[*offset], sizeof (struct saa716x_pll_hdr));
+ saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data);
+ if (header.size != sizeof (struct saa716x_pll_hdr)) {
+ dprintk(SAA716x_ERROR, 1,
+ "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d",
+ header.size,
+ (int)sizeof (struct saa716x_pll_hdr));
+
+ return -1;
+ }
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ header.size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Ext data=%d bytes\n\n",
+ saa716x->pdev->device,
+ header.ext_data);
+
+ *offset += header.size + header.ext_data;
+ return 0;
+}
+
+static int saa716x_channel_decoder_info(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset)
+{
+ struct saa716x_channel_decoder_hdr header;
+
+ memcpy(&header, &buf[*offset], sizeof (struct saa716x_channel_decoder_hdr));
+ saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data);
+ if (header.size != sizeof (struct saa716x_channel_decoder_hdr)) {
+ dprintk(SAA716x_ERROR, 1,
+ "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d",
+ header.size,
+ (int)sizeof (struct saa716x_channel_decoder_hdr));
+
+ return -1;
+ }
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ header.size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Ext data=%d bytes\n\n",
+ saa716x->pdev->device,
+ header.ext_data);
+
+ *offset += header.size + header.ext_data;
+ return 0;
+}
+
+static int saa716x_encoder_info(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset)
+{
+ struct saa716x_encoder_hdr header;
+
+ memcpy(&header, &buf[*offset], sizeof (struct saa716x_encoder_hdr));
+ saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data);
+ if (header.size != sizeof (struct saa716x_encoder_hdr)) {
+ dprintk(SAA716x_ERROR, 1,
+ "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d",
+ header.size,
+ (int)sizeof (struct saa716x_encoder_hdr));
+
+ return -1;
+ }
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ header.size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Ext data=%d bytes\n\n",
+ saa716x->pdev->device,
+ header.ext_data);
+
+ *offset += header.size + header.ext_data;
+ return 0;
+}
+
+static int saa716x_ir_info(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset)
+{
+ struct saa716x_ir_hdr header;
+
+ memcpy(&header, &buf[*offset], sizeof (struct saa716x_ir_hdr));
+ saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data);
+ if (header.size != sizeof (struct saa716x_ir_hdr)) {
+ dprintk(SAA716x_ERROR, 1,
+ "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d",
+ header.size,
+ (int)sizeof (struct saa716x_ir_hdr));
+
+ return -1;
+ }
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ header.size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Ext data=%d bytes\n\n",
+ saa716x->pdev->device,
+ header.ext_data);
+
+ *offset += header.size + header.ext_data;
+ return 0;
+}
+
+static int saa716x_eeprom_info(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset)
+{
+ struct saa716x_eeprom_hdr header;
+
+ memcpy(&header, &buf[*offset], sizeof (struct saa716x_eeprom_hdr));
+ saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data);
+ if (header.size != sizeof (struct saa716x_eeprom_hdr)) {
+ dprintk(SAA716x_ERROR, 1,
+ "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d",
+ header.size,
+ (int)sizeof (struct saa716x_eeprom_hdr));
+
+ return -1;
+ }
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ header.size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Ext data=%d bytes\n\n",
+ saa716x->pdev->device,
+ header.ext_data);
+
+ *offset += header.size + header.ext_data;
+ return 0;
+}
+
+static int saa716x_filter_info(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset)
+{
+ struct saa716x_filter_hdr header;
+
+ memcpy(&header, &buf[*offset], sizeof (struct saa716x_filter_hdr));
+ saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data);
+ if (header.size != sizeof (struct saa716x_filter_hdr)) {
+ dprintk(SAA716x_ERROR, 1,
+ "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d",
+ header.size,
+ (int)sizeof(struct saa716x_filter_hdr));
+
+ return -1;
+ }
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ header.size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Ext data=%d bytes\n",
+ saa716x->pdev->device,
+ header.ext_data);
+
+ *offset += header.size + header.ext_data;
+ return 0;
+}
+
+static int saa716x_streamdev_info(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset)
+{
+ struct saa716x_streamdev_hdr header;
+
+ memcpy(&header, &buf[*offset], sizeof (struct saa716x_streamdev_hdr));
+ saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data);
+ if (header.size != sizeof (struct saa716x_streamdev_hdr)) {
+ dprintk(SAA716x_ERROR, 1,
+ "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d",
+ header.size,
+ (int)sizeof(struct saa716x_streamdev_hdr));
+
+ return -1;
+ }
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ header.size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Ext data=%d bytes\n",
+ saa716x->pdev->device,
+ header.ext_data);
+
+ *offset += header.size + header.ext_data;
+ return 0;
+}
+
+static int saa716x_unknown_device_info(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset)
+{
+ u8 size;
+ u8 ext_size = 0;
+
+ size = buf[*offset];
+ if (size > 1)
+ ext_size = buf[*offset + size -1];
+
+ saa716x_descriptor_dbg(saa716x, buf, offset, size, ext_size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ size);
+
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Ext data=%d bytes\n\n",
+ saa716x->pdev->device,
+ ext_size);
+
+ *offset += size + ext_size;
+ return 0;
+}
+
+
+static void saa716x_device_dbg(struct saa716x_dev *saa716x,
+ u8 *buf,
+ u32 *offset,
+ u8 size,
+ u8 ext_size,
+ u8 addr_size)
+{
+ int i;
+
+ dprintk(SAA716x_INFO, 0, " ");
+ for (i = 0; i < 53; i++)
+ dprintk(SAA716x_INFO, 0, "-");
+
+ for (i = 0; i < size + ext_size + addr_size; i++) {
+ if ((i % 16) == 0)
+ dprintk(SAA716x_INFO, 0, "\n ");
+ if ((i % 8) == 0)
+ dprintk(SAA716x_INFO, 0, " ");
+ if ((i % 4) == 0)
+ dprintk(SAA716x_INFO, 0, " ");
+
+ dprintk(SAA716x_INFO, 0, "%02x ", buf[*offset + i]);
+ }
+
+ dprintk(SAA716x_INFO, 0, "\n ");
+ for (i = 0; i < 53; i++)
+ dprintk(SAA716x_INFO, 0, "-");
+ dprintk(SAA716x_INFO, 0, "\n");
+
+}
+
+
+static int saa716x_device_info(struct saa716x_dev *saa716x,
+ struct saa716x_devinfo *device,
+ u8 *buf,
+ u32 *offset)
+{
+ u8 address = 0;
+
+ memcpy(device, &buf[*offset], sizeof(struct saa716x_devinfo));
+ if (device->struct_size != sizeof(struct saa716x_devinfo)) {
+ dprintk(SAA716x_ERROR, 1, "ERROR: Device size mismatch! Read=%d bytes, expected=%d bytes",
+ device->struct_size,
+ (int)sizeof(struct saa716x_devinfo));
+
+ return -1;
+ }
+
+ saa716x_device_dbg(saa716x,
+ buf,
+ offset,
+ device->struct_size,
+ device->extd_data_size,
+ device->addr_size);
+
+ *offset += device->struct_size;
+
+ if (device->addr_size) {
+ address = buf[*offset];
+ address >>= 1;
+ *offset += device->addr_size;
+ }
+
+ dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Device @ 0x%02x\n",
+ saa716x->pdev->device,
+ address);
+
+ dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Size=%d bytes\n",
+ saa716x->pdev->device,
+ device->struct_size);
+
+ dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Device ID=0x%02x\n",
+ saa716x->pdev->device,
+ device->device_id);
+
+ dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Master ID=0x%02x\n",
+ saa716x->pdev->device,
+ device->master_devid);
+
+ dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Bus ID=0x%02x\n",
+ saa716x->pdev->device,
+ device->master_busid);
+
+ dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Device type=0x%02x\n",
+ saa716x->pdev->device,
+ device->device_type);
+
+ dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Implementation ID=0x%02x\n",
+ saa716x->pdev->device,
+ device->implem_id);
+
+ dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Path ID=0x%02x\n",
+ saa716x->pdev->device,
+ device->path_id);
+
+ dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: GPIO ID=0x%02x\n",
+ saa716x->pdev->device,
+ device->gpio_id);
+
+ dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Address=%d bytes\n",
+ saa716x->pdev->device,
+ device->addr_size);
+
+ dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Extended data=%d bytes\n\n",
+ saa716x->pdev->device,
+ device->extd_data_size);
+
+ if (device->extd_data_size) {
+ u32 mask;
+
+ mask = 0x00000001;
+ while (mask) {
+ if (device->device_type & mask) {
+ switch (mask) {
+ case DECODER_DEVICE:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found decoder device\n",
+ saa716x->pdev->device);
+
+ saa716x_decoder_info(saa716x, buf, offset);
+ break;
+
+ case GPIO_SOURCE:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found GPIO device\n",
+ saa716x->pdev->device);
+
+ saa716x_gpio_info(saa716x, buf, offset);
+ break;
+
+ case VIDEO_DECODER:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found Video Decoder device\n",
+ saa716x->pdev->device);
+
+ saa716x_video_decoder_info(saa716x, buf, offset);
+ break;
+
+ case AUDIO_DECODER:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found Audio Decoder device\n",
+ saa716x->pdev->device);
+
+ saa716x_audio_decoder_info(saa716x, buf, offset);
+ break;
+
+ case EVENT_SOURCE:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found Event source\n",
+ saa716x->pdev->device);
+
+ saa716x_event_source_info(saa716x, buf, offset);
+ break;
+
+ case CROSSBAR:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found Crossbar device\n",
+ saa716x->pdev->device);
+
+ saa716x_crossbar_info(saa716x, buf, offset);
+ break;
+
+ case TUNER_DEVICE:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found Tuner device\n",
+ saa716x->pdev->device);
+
+ saa716x_tuner_info(saa716x, buf, offset);
+ break;
+
+ case PLL_DEVICE:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found PLL device\n",
+ saa716x->pdev->device);
+
+ saa716x_pll_info(saa716x, buf, offset);
+ break;
+
+ case CHANNEL_DECODER:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found Channel Demodulator device\n",
+ saa716x->pdev->device);
+
+ saa716x_channel_decoder_info(saa716x, buf, offset);
+ break;
+
+ case RDS_DECODER:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found RDS Decoder device\n",
+ saa716x->pdev->device);
+
+ saa716x_unknown_device_info(saa716x, buf, offset);
+ break;
+
+ case ENCODER_DEVICE:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found Encoder device\n",
+ saa716x->pdev->device);
+
+ saa716x_encoder_info(saa716x, buf, offset);
+ break;
+
+ case IR_DEVICE:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found IR device\n",
+ saa716x->pdev->device);
+
+ saa716x_ir_info(saa716x, buf, offset);
+ break;
+
+ case EEPROM_DEVICE:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found EEPROM device\n",
+ saa716x->pdev->device);
+
+ saa716x_eeprom_info(saa716x, buf, offset);
+ break;
+
+ case NOISE_FILTER:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found Noise filter device\n",
+ saa716x->pdev->device);
+
+ saa716x_filter_info(saa716x, buf, offset);
+ break;
+
+ case LNx_DEVICE:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found LNx device\n",
+ saa716x->pdev->device);
+
+ saa716x_unknown_device_info(saa716x, buf, offset);
+ break;
+
+ case STREAM_DEVICE:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found streaming device\n",
+ saa716x->pdev->device);
+
+ saa716x_streamdev_info(saa716x, buf, offset);
+ break;
+
+ case CONFIGSPACE_DEVICE:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found Configspace device\n",
+ saa716x->pdev->device);
+
+ saa716x_unknown_device_info(saa716x, buf, offset);
+ break;
+
+ default:
+ dprintk(SAA716x_NOTICE, 0,
+ " SAA%02x ROM: Found unknown device\n",
+ saa716x->pdev->device);
+
+ saa716x_unknown_device_info(saa716x, buf, offset);
+ break;
+ }
+ }
+ mask <<= 1;
+ }
+ }
+
+ dprintk(SAA716x_NOTICE, 0, "\n");
+
+ return 0;
+}
+
+int saa716x_eeprom_data(struct saa716x_dev *saa716x)
+{
+ struct saa716x_romhdr rom_header;
+ struct saa716x_devinfo *device;
+
+ u8 buf[1024];
+ int i, ret = 0;
+ u32 offset = 0;
+
+ /* dump */
+ ret = saa716x_read_rombytes(saa716x, saa716x->id_offst, saa716x->id_len + 8, buf);
+ if (ret < 0) {
+ dprintk(SAA716x_ERROR, 1, "EEPROM Read error <%d>", ret);
+ goto err0;
+ }
+
+ /* Get header */
+ ret = saa716x_eeprom_header(saa716x, &rom_header, buf, &offset);
+ if (ret != 0) {
+ dprintk(SAA716x_ERROR, 1, "ERROR: Header Read failed <%d>", ret);
+ goto err0;
+ }
+
+ /* allocate for device info */
+ device = kzalloc(sizeof (struct saa716x_devinfo) * rom_header.devices, GFP_KERNEL);
+ if (device == NULL) {
+ dprintk(SAA716x_ERROR, 1, "ERROR: out of memory");
+ goto err0;
+ }
+
+ for (i = 0; i < rom_header.devices; i++) {
+ dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: ===== Device %d =====\n",
+ saa716x->pdev->device,
+ i);
+
+ ret = saa716x_device_info(saa716x, &device[i], buf, &offset);
+ if (ret != 0) {
+ dprintk(SAA716x_ERROR, 1, "ERROR: Device info read failed <%d>", ret);
+ goto err1;
+ }
+ }
+
+ kfree(device);
+
+ return 0;
+
+err1:
+ kfree(device);
+
+err0:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(saa716x_eeprom_data);
diff --git a/drivers/media/common/saa716x/saa716x_rom.h b/drivers/media/common/saa716x/saa716x_rom.h
new file mode 100644
index 0000000..6bb317f
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_rom.h
@@ -0,0 +1,253 @@
+#ifndef __SAA716x_ROM_H
+#define __SAA716x_ROM_H
+
+
+#define MSB(__x) ((__x >> 8) & 0xff)
+#define LSB(__x) (__x & 0xff)
+
+#define DUMP_BYTES 0xf0
+#define DUMP_OFFST 0x000
+
+struct saa716x_dev;
+
+struct saa716x_romhdr {
+ u16 header_size;
+ u8 compression;
+ u8 version;
+ u16 data_size;
+ u8 devices;
+ u8 checksum;
+} __attribute__((packed));
+
+struct saa716x_devinfo {
+ u8 struct_size;
+ u8 device_id;
+ u8 master_devid;
+ u8 master_busid;
+ u32 device_type;
+ u16 implem_id;
+ u8 path_id;
+ u8 gpio_id;
+ u16 addr_size;
+ u16 extd_data_size;
+} __attribute__((packed));
+
+enum saa716x_device_types {
+ DECODER_DEVICE = 0x00000001,
+ GPIO_SOURCE = 0x00000002,
+ VIDEO_DECODER = 0x00000004,
+ AUDIO_DECODER = 0x00000008,
+ EVENT_SOURCE = 0x00000010,
+ CROSSBAR = 0x00000020,
+ TUNER_DEVICE = 0x00000040,
+ PLL_DEVICE = 0x00000080,
+ CHANNEL_DECODER = 0x00000100,
+ RDS_DECODER = 0x00000200,
+ ENCODER_DEVICE = 0x00000400,
+ IR_DEVICE = 0x00000800,
+ EEPROM_DEVICE = 0x00001000,
+ NOISE_FILTER = 0x00002000,
+ LNx_DEVICE = 0x00004000,
+ STREAM_DEVICE = 0x00010000,
+ CONFIGSPACE_DEVICE = 0x80000000
+};
+
+struct saa716x_decoder_hdr {
+ u8 size;
+ u8 ext_data;
+};
+
+struct saa716x_decoder_info {
+ struct saa716x_decoder_hdr decoder_hdr;
+ u8 *ext_data;
+};
+
+struct saa716x_gpio_hdr {
+ u8 size;
+ u8 pins;
+ u8 rsvd;
+ u8 ext_data;
+};
+
+struct saa716x_gpio_info {
+ struct saa716x_gpio_hdr gpio_hdr;
+ u8 *ext_data;
+};
+
+struct saa716x_video_decoder_hdr {
+ u8 size;
+ u8 video_port0;
+ u8 video_port1;
+ u8 video_port2;
+ u8 vbi_port_id;
+ u8 video_port_type;
+ u8 vbi_port_type;
+ u8 encoder_port_type;
+ u8 video_output;
+ u8 vbi_output;
+ u8 encoder_output;
+ u8 ext_data;
+};
+
+struct saa716x_video_decoder_info {
+ struct saa716x_video_decoder_hdr decoder_hdr;
+ u8 *ext_data;
+};
+
+struct saa716x_audio_decoder_hdr {
+ u8 size;
+ u8 port;
+ u8 output;
+ u8 ext_data;
+};
+
+struct saa716x_audio_decoder_info {
+ struct saa716x_audio_decoder_hdr decoder_hdr;
+ u8 *ext_data;
+};
+
+struct saa716x_evsrc_hdr {
+ u8 size;
+ u8 master_devid;
+ u16 condition_id;
+ u8 rsvd;
+ u8 ext_data;
+};
+
+struct saa716x_evsrc_info {
+ struct saa716x_evsrc_hdr evsrc_hdr;
+ u8 *ext_data;
+};
+
+enum saa716x_input_pair_type {
+ TUNER_SIF = 0x00,
+ TUNER_LINE = 0x01,
+ TUNER_SPDIF = 0x02,
+ TUNER_NONE = 0x03,
+ CVBS_LINE = 0x04,
+ CVBS_SPDIF = 0x05,
+ CVBS_NONE = 0x06,
+ YC_LINE = 0x07,
+ YC_SPDIF = 0x08,
+ YC_NONE = 0x09,
+ YPbPr_LINE = 0x0a,
+ YPbPr_SPDIF = 0x0b,
+ YPbPr_NONE = 0x0c,
+ NO_LINE = 0x0d,
+ NO_SPDIF = 0x0e,
+ RGB_LINE = 0x0f,
+ RGB_SPDIF = 0x10,
+ RGB_NONE = 0x11
+};
+
+struct saa716x_xbar_pair_info {
+ u8 pair_input_type;
+ u8 video_input_id;
+ u8 audio_input_id;
+};
+
+struct saa716x_xbar_hdr {
+ u8 size;
+ u8 pair_inputs;
+ u8 pair_route_default;
+ u8 ext_data;
+};
+
+struct saa716x_xbar_info {
+ struct saa716x_xbar_hdr xbar_hdr;
+ struct saa716x_xbar_pair_info *pair_info;
+ u8 *ext_data;
+};
+
+struct saa716x_tuner_hdr {
+ u8 size;
+ u8 ext_data;
+};
+
+struct saa716x_tuner_info {
+ struct saa716x_tuner_hdr tuner_hdr;
+ u8 *ext_data;
+};
+
+struct saa716x_pll_hdr {
+ u8 size;
+ u8 ext_data;
+};
+
+struct saa716x_pll_info {
+ struct saa716x_pll_hdr pll_hdr;
+ u8 *ext_data;
+};
+
+struct saa716x_channel_decoder_hdr {
+ u8 size;
+ u8 port;
+ u8 ext_data;
+};
+
+struct saa716x_channel_decoder_info {
+ struct saa716x_channel_decoder_hdr channel_dec_hdr;
+ u8 *ext_data;
+};
+
+struct saa716x_encoder_hdr {
+ u8 size;
+ u8 stream_port0;
+ u8 stream_port1;
+ u8 ext_data;
+};
+
+struct saa716x_encoder_info {
+ struct saa716x_encoder_hdr encoder_hdr;
+ u8 *ext_data;
+};
+
+struct saa716x_ir_hdr {
+ u8 size;
+ u8 ir_caps;
+ u8 ext_data;
+};
+
+struct saa716x_ir_info {
+ struct saa716x_ir_hdr ir_hdr;
+ u8 *ext_data;
+};
+
+struct saa716x_eeprom_hdr {
+ u8 size;
+ u8 rel_device;
+ u8 ext_data;
+};
+
+struct saa716x_eeprom_info {
+ struct saa716x_eeprom_hdr eeprom_hdr;
+ u8 *ext_data;
+};
+
+struct saa716x_filter_hdr {
+ u8 size;
+ u8 video_decoder;
+ u8 audio_decoder;
+ u8 event_source;
+ u8 ext_data;
+};
+
+struct saa716x_filter_info {
+ struct saa716x_filter_hdr filter_hdr;
+ u8 *ext_data;
+};
+
+struct saa716x_streamdev_hdr {
+ u8 size;
+ u8 ext_data;
+};
+
+struct saa716x_streamdev_info {
+ struct saa716x_streamdev_hdr streamdev_hdr;
+ u8 *ext_data;
+};
+
+extern int saa716x_dump_eeprom(struct saa716x_dev *saa716x);
+extern int saa716x_eeprom_data(struct saa716x_dev *saa716x);
+
+#endif /* __SAA716x_ROM_H */
diff --git a/drivers/media/common/saa716x/saa716x_spi.c b/drivers/media/common/saa716x/saa716x_spi.c
new file mode 100644
index 0000000..8859454
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_spi.c
@@ -0,0 +1,313 @@
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+
+#include <linux/spi/spi.h>
+
+#include "saa716x_mod.h"
+
+#include "saa716x_spi_reg.h"
+#include "saa716x_spi.h"
+#include "saa716x_priv.h"
+
+#if 0 // not needed atm
+int saa716x_spi_irqevent(struct saa716x_dev *saa716x)
+{
+ u32 stat, mask;
+
+ BUG_ON(saa716x == NULL);
+
+ stat = SAA716x_EPRD(SPI, SPI_STATUS);
+ mask = SAA716x_EPRD(SPI, SPI_CONTROL_REG) & SPI_SERIAL_INTER_ENABLE;
+ if ((!stat && !mask))
+ return -1;
+
+ dprintk(SAA716x_DEBUG, 0, "SPI event: Stat=<%02x>", stat);
+
+ if (stat & SPI_TRANSFER_FLAG)
+ dprintk(SAA716x_DEBUG, 0, "<TXFER> ");
+ if (stat & SPI_WRITE_COLLISSION)
+ dprintk(SAA716x_DEBUG, 0, "<WCOLL> ");
+ if (stat & SPI_READ_OVERRUN)
+ dprintk(SAA716x_DEBUG, 0, "<ROFLW> ");
+ if (stat & SPI_MODE_FAULT)
+ dprintk(SAA716x_DEBUG, 0, "<FAULT> ");
+ if (stat & SPI_SLAVE_ABORT)
+ dprintk(SAA716x_DEBUG, 0, "<ABORT> ");
+
+ return 0;
+}
+#endif
+
+void saa716x_spi_write(struct saa716x_dev *saa716x, const u8 *data, int length)
+{
+ int i;
+ u32 value;
+ int rounds;
+
+ for (i = 0; i < length; i++) {
+ SAA716x_EPWR(SPI, SPI_DATA, data[i]);
+ rounds = 0;
+ value = SAA716x_EPRD(SPI, SPI_STATUS);
+
+ while ((value & SPI_TRANSFER_FLAG) == 0 && rounds < 5000) {
+ value = SAA716x_EPRD(SPI, SPI_STATUS);
+ rounds++;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(saa716x_spi_write);
+
+#if 0 // not needed atm
+static int saa716x_spi_status(struct saa716x_dev *saa716x, u32 *status)
+{
+ u32 stat;
+
+ stat = SAA716x_EPRD(SPI, SPI_STATUS);
+
+ if (stat & SPI_TRANSFER_FLAG)
+ dprintk(SAA716x_DEBUG, 1, "Transfer complete <%02x>", stat);
+
+ if (stat & SPI_WRITE_COLLISSION)
+ dprintk(SAA716x_DEBUG, 1, "Write collission <%02x>", stat);
+
+ if (stat & SPI_READ_OVERRUN)
+ dprintk(SAA716x_DEBUG, 1, "Read Overrun <%02x>", stat);
+
+ if (stat & SPI_MODE_FAULT)
+ dprintk(SAA716x_DEBUG, 1, "MODE fault <%02x>", stat);
+
+ if (stat & SPI_SLAVE_ABORT)
+ dprintk(SAA716x_DEBUG, 1, "SLAVE abort <%02x>", stat);
+
+ *status = stat;
+
+ return 0;
+}
+
+#define SPI_CYCLE_TIMEOUT 100
+
+static int saa716x_spi_xfer(struct saa716x_dev *saa716x, u32 *data)
+{
+ u32 i, status = 0;
+
+ /* write data and wait for completion */
+ SAA716x_EPWR(SPI, SPI_DATA, data[i]);
+ for (i = 0; i < SPI_CYCLE_TIMEOUT; i++) {
+ msleep(10);
+ saa716x_spi_status(saa716x, &status);
+#if 0
+ if (status & SPI_TRANSFER_FLAG) {
+ data = SAA716x_EPRD(SPI, SPI_DATA);
+ return 0;
+ }
+#endif
+ if (status & (SPI_WRITE_COLLISSION |
+ SPI_READ_OVERRUN |
+ SPI_MODE_FAULT |
+ SPI_SLAVE_ABORT))
+
+ return -EIO;
+ }
+
+ return -EIO;
+}
+
+#if 0
+static int saa716x_spi_wr(struct saa716x_dev *saa716x, const u8 *data, int length)
+{
+ struct saa716x_spi_config *config = saa716x->spi_config;
+ u32 gpio_mask;
+ int ret = 0;
+
+ // protect against multiple access
+ spin_lock(&saa716x->gpio_lock);
+
+ // configure the module
+ saa716x_spi_config(saa716x);
+
+ // check input
+
+ // change polarity of GPIO if active high
+ if (config->active_hi) {
+ select = 1;
+ release = 0;
+ }
+
+ // configure GPIO, first set output register to low selected level
+ saa716x_gpio_write(saa716x, gpio, select);
+
+ // set mode register to register controlled (0)
+ gpio_mask = (1 << gpio);
+ saa716x_set_gpio_mode(saa716x, gpio_mask, 0);
+
+ // configure bit as output (0)
+ saa716x_gpio_ctl(saa716x, gpio_mask, 0);
+
+ // wait at least 500ns before sending a byte
+ msleep(1);
+
+ // send command
+ for (i = 0; i < dwCommandSize; i++) {
+ ucData = 0;
+// dwStatus = TransferData(pucCommand[i], &ucData);
+ ret = saa716x_spi_xfer(saa716x);
+ //tmDBGPRINTEx(4,("Info: Command 0x%x ", pucCommand[i] ));
+
+ /* If command length > 1, disable CS at the end of each command.
+ * But after the last command byte CS must be left active!
+ */
+ if ((dwCommandSize > 1) && (i < dwCommandSize - 1)) {
+
+ saa716x_gpio_write(saa716x, gpio, release);
+ msleep(1); /* 500 nS minimum */
+ saa716x_gpio_write(saa716x, gpio, select);
+ }
+
+ if (ret != 0) {
+ dprintk(SAA716x_ERROR, 1, "ERROR: Command transfer failed");
+ msleep(1); /* 500 nS minimum */
+ saa716x_gpio_write(saa716x, gpio, release); /* release GPIO */
+ spin_unlock(&saa716x->spi_lock);
+ return ret;
+ }
+
+ if (config->LSB_first)
+ dwTransferByte++;
+ else
+ dwTransferByte--;
+ }
+
+// assume that the byte order is the same as the bit order
+
+// send read address
+
+// send data
+
+// wait at least 500ns before releasing slave
+
+// release GPIO pin
+
+ // release spinlock
+ spin_unlock(&saa716x->gpio_lock);
+}
+#endif
+
+#define MODEBITS (SPI_CPOL | SPI_CPHA)
+
+static int saa716x_spi_setup(struct spi_device *spi)
+{
+ struct spi_master *master = spi->master;
+ struct saa716x_spi_state *saa716x_spi = spi_master_get_devdata(master);
+ struct saa716x_dev *saa716x = saa716x_spi->saa716x;
+ struct saa716x_spi_config *config = &saa716x->spi_config;
+
+ u8 control = 0;
+
+ if (spi->mode & ~MODEBITS) {
+ dprintk(SAA716x_ERROR, 1, "ERROR: Unsupported MODE bits <%x>",
+ spi->mode & ~MODEBITS);
+
+ return -EINVAL;
+ }
+
+ SAA716x_EPWR(SPI, SPI_CLOCK_COUNTER, config->clk_count);
+
+ control |= SPI_MODE_SELECT; /* SPI Master */
+
+ if (config->LSB_first)
+ control |= SPI_LSB_FIRST_ENABLE;
+
+ if (config->clk_pol)
+ control |= SPI_CLOCK_POLARITY;
+
+ if (config->clk_pha)
+ control |= SPI_CLOCK_PHASE;
+
+ SAA716x_EPWR(SPI, SPI_CONTROL_REG, control);
+
+ return 0;
+}
+
+static void saa716x_spi_cleanup(struct spi_device *spi)
+{
+
+}
+
+static int saa716x_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+ struct spi_master *master = spi->master;
+ struct saa716x_spi_state *saa716x_spi = spi_master_get_devdata(master);
+ struct saa716x_dev *saa716x = saa716x_spi->saa716x;
+ unsigned long flags;
+
+ spin_lock_irqsave(&saa716x->gpio_lock, flags);
+#if 0
+ if (saa716x_spi->run == QUEUE_STOPPED) {
+ spin_unlock_irqrestore(&saa716x_spi->lock, flags);
+ return -ESHUTDOWN;
+ }
+
+ msg->actual_length = 0;
+ msg->status = -EINPROGRESS;
+ msg->state = START_STATE;
+
+ list_add_tail(&msg->queue, &saa716x_spi->queue);
+
+ if (saa716x_spi->run == QUEUE_RUNNING && !saa716x_spi->busy)
+ queue_work(saa716x_spi->workqueue, &saa716x_spi->pump_messages);
+#endif
+ spin_unlock_irqrestore(&saa716x->gpio_lock, flags);
+
+ return 0;
+}
+
+int saa716x_spi_init(struct saa716x_dev *saa716x)
+{
+ struct pci_dev *pdev = saa716x->pdev;
+ struct spi_master *master;
+ struct saa716x_spi_state *saa716x_spi;
+ int ret;
+
+ dprintk(SAA716x_DEBUG, 1, "Initializing SAA%02x I2C Core",
+ saa716x->pdev->device);
+
+ master = spi_alloc_master(&pdev->dev, sizeof (struct saa716x_spi_state));
+ if (master == NULL) {
+ dprintk(SAA716x_ERROR, 1, "ERROR: Cannot allocate SPI Master!");
+ return -ENOMEM;
+ }
+
+ saa716x_spi = spi_master_get_devdata(master);
+ saa716x_spi->master = master;
+ saa716x_spi->saa716x = saa716x;
+ saa716x->saa716x_spi = saa716x_spi;
+
+ master->bus_num = pdev->bus->number;
+ master->num_chipselect = 1; /* TODO! use config */
+ master->cleanup = saa716x_spi_cleanup;
+ master->setup = saa716x_spi_setup;
+ master->transfer = saa716x_spi_transfer;
+
+ ret = spi_register_master(master);
+ if (ret != 0) {
+ dprintk(SAA716x_ERROR, 1, "ERROR: registering SPI Master!");
+ goto err;
+ }
+err:
+ spi_master_put(master);
+ return ret;
+}
+EXPORT_SYMBOL(saa716x_spi_init);
+
+void saa716x_spi_exit(struct saa716x_dev *saa716x)
+{
+ struct saa716x_spi_state *saa716x_spi = saa716x->saa716x_spi;
+
+ spi_unregister_master(saa716x_spi->master);
+ dprintk(SAA716x_DEBUG, 1, "SAA%02x SPI succesfully removed", saa716x->pdev->device);
+}
+EXPORT_SYMBOL(saa716x_spi_exit);
+#endif
+
diff --git a/drivers/media/common/saa716x/saa716x_spi.h b/drivers/media/common/saa716x/saa716x_spi.h
new file mode 100644
index 0000000..0060c22
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_spi.h
@@ -0,0 +1,23 @@
+#ifndef __SAA716x_SPI_H
+#define __SAA716x_SPI_H
+
+struct saa716x_dev;
+
+struct saa716x_spi_config {
+ u8 clk_count;
+ u8 clk_pol:1;
+ u8 clk_pha:1;
+ u8 LSB_first:1;
+};
+
+struct saa716x_spi_state {
+ struct spi_master *master;
+ struct saa716x_dev *saa716x;
+};
+
+extern void saa716x_spi_write(struct saa716x_dev *saa716x, const u8 *data, int length);
+
+extern int saa716x_spi_init(struct saa716x_dev *saa716x);
+extern void saa716x_spi_exit(struct saa716x_dev *saa716x);
+
+#endif /* __SAA716x_SPI_H */
diff --git a/drivers/media/common/saa716x/saa716x_spi_reg.h b/drivers/media/common/saa716x/saa716x_spi_reg.h
new file mode 100644
index 0000000..c51abce
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_spi_reg.h
@@ -0,0 +1,27 @@
+#ifndef __SAA716x_SPI_REG_H
+#define __SAA716x_SPI_REG_H
+
+/* -------------- SPI Registers -------------- */
+
+#define SPI_CONTROL_REG 0x000
+#define SPI_SERIAL_INTER_ENABLE (0x00000001 << 7)
+#define SPI_LSB_FIRST_ENABLE (0x00000001 << 6)
+#define SPI_MODE_SELECT (0x00000001 << 5)
+#define SPI_CLOCK_POLARITY (0x00000001 << 4)
+#define SPI_CLOCK_PHASE (0x00000001 << 3)
+
+#define SPI_STATUS 0x004
+#define SPI_TRANSFER_FLAG (0x00000001 << 7)
+#define SPI_WRITE_COLLISSION (0x00000001 << 6)
+#define SPI_READ_OVERRUN (0x00000001 << 5)
+#define SPI_MODE_FAULT (0x00000001 << 4)
+#define SPI_SLAVE_ABORT (0x00000001 << 3)
+
+#define SPI_DATA 0x008
+#define SPI_BIDI_DATA (0x000000ff << 0)
+
+#define SPI_CLOCK_COUNTER 0x00c
+#define SPI_CLOCK (0x00000001 << 0)
+
+
+#endif /* __SAA716x_SPI_REG_H */
diff --git a/drivers/media/common/saa716x/saa716x_vip.c b/drivers/media/common/saa716x/saa716x_vip.c
new file mode 100644
index 0000000..4cd4c81
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_vip.c
@@ -0,0 +1,23 @@
+#include <linux/kernel.h>
+
+#include "saa716x_mod.h"
+
+#include "saa716x_vip_reg.h"
+#include "saa716x_spi.h"
+#include "saa716x_priv.h"
+
+void saa716x_vipint_disable(struct saa716x_dev *saa716x)
+{
+ SAA716x_EPWR(VI0, INT_ENABLE, 0); /* disable VI 0 IRQ */
+ SAA716x_EPWR(VI1, INT_ENABLE, 0); /* disable VI 1 IRQ */
+ SAA716x_EPWR(VI0, INT_CLR_STATUS, 0x3ff); /* clear IRQ */
+ SAA716x_EPWR(VI1, INT_CLR_STATUS, 0x3ff); /* clear IRQ */
+}
+EXPORT_SYMBOL_GPL(saa716x_vipint_disable);
+
+void saa716x_vip_disable(struct saa716x_dev *saa716x)
+{
+ SAA716x_EPWR(VI0, VIP_POWER_DOWN, VI_PWR_DWN);
+ SAA716x_EPWR(VI1, VIP_POWER_DOWN, VI_PWR_DWN);
+}
+EXPORT_SYMBOL_GPL(saa716x_vip_disable);
diff --git a/drivers/media/common/saa716x/saa716x_vip.h b/drivers/media/common/saa716x/saa716x_vip.h
new file mode 100644
index 0000000..55c6a1a
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_vip.h
@@ -0,0 +1,9 @@
+#ifndef __SAA716x_VIP_H
+#define __SAA716x_VIP_H
+
+struct saa716x_dev;
+
+extern void saa716x_vipint_disable(struct saa716x_dev *saa716x);
+extern void saa716x_vip_disable(struct saa716x_dev *saa716x);
+
+#endif /* __SAA716x_VIP_H */
diff --git a/drivers/media/common/saa716x/saa716x_vip_reg.h b/drivers/media/common/saa716x/saa716x_vip_reg.h
new file mode 100644
index 0000000..2d773bd
--- /dev/null
+++ b/drivers/media/common/saa716x/saa716x_vip_reg.h
@@ -0,0 +1,127 @@
+#ifndef __SAA716x_VIP_REG_H
+#define __SAA716x_VIP_REG_H
+
+/* -------------- VIP Registers -------------- */
+
+#define VI_MODE 0x000
+#define VID_CFEN (0x00000003 << 30)
+#define VID_OSM (0x00000001 << 29)
+#define VID_FSEQ (0x00000001 << 28)
+#define AUX_CFEN (0x00000003 << 26)
+#define AUX_OSM (0x00000001 << 25)
+#define AUX_FSEQ (0x00000001 << 24)
+#define AUX_ANC_DATA (0x00000003 << 22)
+#define AUX_ANC_RAW (0x00000001 << 21)
+#define RST_ON_ERR (0x00000001 << 17)
+#define SOFT_RESET (0x00000001 << 16)
+#define IFF_CLAMP (0x00000001 << 14)
+#define IFF_MODE (0x00000003 << 12)
+#define DFF_CLAMP (0x00000001 << 10)
+#define DFF_MODE (0x00000003 << 8)
+#define HSP_CLAMP (0x00000001 << 3)
+#define HSP_RGB (0x00000001 << 2)
+#define HSP_MODE (0x00000003 << 0)
+
+#define RCRB_CTRL 0x004
+#define RCRB_CFG_ADDR 0x008
+#define RCRB_CFG_EXT_ADDR 0x00c
+#define RCRB_IO_ADDR 0x010
+#define RCRB_MEM_LADDR 0x014
+#define RCRB_MEM_UADDR 0x018
+#define RCRB_DATA 0x01c
+#define RCRB_MASK 0x020
+#define RCRB_MSG_HDR 0x040
+#define RCRB_MSG_PL0 0x044
+#define RCRB_MSG_PL1 0x048
+
+#define ID_MASK0 0x020
+#define VI_ID_MASK_0 (0x000000ff << 8)
+#define VI_DATA_ID_0 (0x000000ff << 0)
+
+#define ID_MASK1 0x024
+#define VI_ID_MASK_1 (0x000000ff << 8)
+#define VI_DATA_ID_1 (0x000000ff << 0)
+
+#define VIP_LINE_THRESH 0x040
+#define VI_LCTHR (0x000007ff << 0)
+
+#define VIN_FORMAT 0x100
+#define VI_VSRA (0x00000003 << 30)
+#define VI_SYNCHD (0x00000001 << 25)
+#define VI_DUAL_STREAM (0x00000001 << 24)
+#define VI_NHDAUX (0x00000001 << 20)
+#define VI_NPAR (0x00000001 << 19)
+#define VI_VSEL (0x00000003 << 14)
+#define VI_TWOS (0x00000001 << 13)
+#define VI_TPG (0x00000001 << 12)
+#define VI_FREF (0x00000001 << 10)
+#define VI_FTGL (0x00000001 << 9)
+#define VI_SF (0x00000001 << 3)
+#define VI_FZERO (0x00000001 << 2)
+#define VI_REVS (0x00000001 << 1)
+#define VI_REHS (0x00000001 << 0)
+
+#define TC76543210 0x800
+#define TCFEDCBA98 0x804
+#define PHYCFG 0x900
+#define CONFIG 0xfd4
+#define INT_ENABLE_CLR 0xfd8
+#define INT_ENABLE_SET 0xfdc
+
+
+#define INT_STATUS 0xfe0
+#define VI_STAT_FID_AUX (0x00000001 << 31)
+#define VI_STAT_FID_VID (0x00000001 << 30)
+#define VI_STAT_FID_VPI (0x00000001 << 29)
+#define VI_STAT_LINE_COUNT (0x00000fff << 16)
+#define VI_STAT_AUX_OVRFLW (0x00000001 << 9)
+#define VI_STAT_VID_OVRFLW (0x00000001 << 8)
+#define VI_STAT_WIN_SEQBRK (0x00000001 << 7)
+#define VI_STAT_FID_SEQBRK (0x00000001 << 6)
+#define VI_STAT_LINE_THRESH (0x00000001 << 5)
+#define VI_STAT_AUX_WRAP (0x00000001 << 4)
+#define VI_STAT_AUX_START_IN (0x00000001 << 3)
+#define VI_STAT_AUX_END_OUT (0x00000001 << 2)
+#define VI_STAT_VID_START_IN (0x00000001 << 1)
+#define VI_STAT_VID_END_OUT (0x00000001 << 0)
+
+#define INT_ENABLE 0xfe4
+#define VI_ENABLE_AUX_OVRFLW (0x00000001 << 9)
+#define VI_ENABLE_VID_OVRFLW (0x00000001 << 8)
+#define VI_ENABLE_WIN_SEQBRK (0x00000001 << 7)
+#define VI_ENABLE_FID_SEQBRK (0x00000001 << 6)
+#define VI_ENABLE_LINE_THRESH (0x00000001 << 5)
+#define VI_ENABLE_AUX_WRAP (0x00000001 << 4)
+#define VI_ENABLE_AUX_START_IN (0x00000001 << 3)
+#define VI_ENABLE_AUX_END_OUT (0x00000001 << 2)
+#define VI_ENABLE_VID_START_IN (0x00000001 << 1)
+#define VI_ENABLE_VID_END_OUT (0x00000001 << 0)
+
+#define INT_CLR_STATUS 0xfe8
+#define VI_CLR_STATUS_AUX_OVRFLW (0x00000001 << 9)
+#define VI_CLR_STATUS_VID_OVRFLW (0x00000001 << 8)
+#define VI_CLR_STATUS_WIN_SEQBRK (0x00000001 << 7)
+#define VI_CLR_STATUS_FID_SEQBRK (0x00000001 << 6)
+#define VI_CLR_STATUS_LINE_THRESH (0x00000001 << 5)
+#define VI_CLR_STATUS_AUX_WRAP (0x00000001 << 4)
+#define VI_CLR_STATUS_AUX_START_IN (0x00000001 << 3)
+#define VI_CLR_STATUS_AUX_END_OUT (0x00000001 << 2)
+#define VI_CLR_STATUS_VID_START_IN (0x00000001 << 1)
+#define VI_CLR_STATUS_VID_END_OUT (0x00000001 << 0)
+
+#define INT_SET_STATUS 0xfec
+#define VI_SET_STATUS_AUX_OVRFLW (0x00000001 << 9)
+#define VI_SET_STATUS_VID_OVRFLW (0x00000001 << 8)
+#define VI_SET_STATUS_WIN_SEQBRK (0x00000001 << 7)
+#define VI_SET_STATUS_FID_SEQBRK (0x00000001 << 6)
+#define VI_SET_STATUS_LINE_THRESH (0x00000001 << 5)
+#define VI_SET_STATUS_AUX_WRAP (0x00000001 << 4)
+#define VI_SET_STATUS_AUX_START_IN (0x00000001 << 3)
+#define VI_SET_STATUS_AUX_END_OUT (0x00000001 << 2)
+#define VI_SET_STATUS_VID_START_IN (0x00000001 << 1)
+#define VI_SET_STATUS_VID_END_OUT (0x00000001 << 0)
+
+#define VIP_POWER_DOWN 0xff4
+#define VI_PWR_DWN (0x00000001 << 31)
+
+#endif /* __SAA716x_VIP_REG_H */
diff --git a/drivers/media/dvb-frontends/ds3103.h b/drivers/media/dvb-frontends/ds3103.h
new file mode 100644
index 0000000..e52740c
--- /dev/null
+++ b/drivers/media/dvb-frontends/ds3103.h
@@ -0,0 +1,47 @@
+/*
+ Montage Technology DS3103 - DVBS/S2 Demodulator driver
+
+ 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 DS3103_H
+#define DS3103_H
+
+#include <linux/dvb/frontend.h>
+
+struct ds3103_config {
+ /* the demodulator's i2c address */
+ u8 demod_address;
+ u8 ci_mode;
+ /* Set device param to start dma */
+ int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+ /* Hook for Lock LED */
+ void (*set_lock_led)(struct dvb_frontend *fe, int offon);
+};
+
+#if defined(CONFIG_DVB_DS3103) || \
+ (defined(CONFIG_DVB_DS3103_MODULE) && defined(MODULE))
+extern struct dvb_frontend *ds3103_attach(const struct ds3103_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline
+struct dvb_frontend *ds3103_attach(const struct ds3103_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_DS3103 */
+#endif /* DS3103_H */
diff --git a/drivers/media/dvb-frontends/ts2022.h b/drivers/media/dvb-frontends/ts2022.h
new file mode 100644
index 0000000..c894edb
--- /dev/null
+++ b/drivers/media/dvb-frontends/ts2022.h
@@ -0,0 +1,51 @@
+ /*
+ Driver for Montage TS2022 DVBS/S2 Silicon tuner
+
+ Copyright (C) 2012 Tomazzo Muzumici
+
+ 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 __DVB_TS2022_H__
+#define __DVB_TS2022_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/**
+ * Attach a ts2022 tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param addr i2c address of the tuner.
+ * @param i2c i2c adapter to use.
+ * @return FE pointer on success, NULL on failure.
+ */
+#if defined(CONFIG_DVB_TS2022) || (defined(CONFIG_DVB_TS2022_MODULE) \
+ && defined(MODULE))
+extern struct dvb_frontend *ts2022_attach(struct dvb_frontend *fe, int addr,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *ts2022_attach(struct dvb_frontend *fe,
+ int addr,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_TS2022 */
+
+#endif /* __DVB_TS2022_H__ */
diff --git a/include/uapi/linux/dvb/osd.h b/include/uapi/linux/dvb/osd.h
index 880e684..edd728c 100644
--- a/include/uapi/linux/dvb/osd.h
+++ b/include/uapi/linux/dvb/osd.h
@@ -141,4 +141,20 @@ typedef struct osd_cap_s {
#define OSD_SEND_CMD _IOW('o', 160, osd_cmd_t)
#define OSD_GET_CAPABILITY _IOR('o', 161, osd_cap_t)
+typedef struct osd_raw_cmd_s {
+ const void __user *cmd_data;
+ int cmd_len;
+ void __user *result_data;
+ int result_len;
+} osd_raw_cmd_t;
+
+typedef struct osd_raw_data_s {
+ const void __user *data_buffer;
+ int data_length;
+ int data_handle;
+} osd_raw_data_t;
+
+#define OSD_RAW_CMD _IOWR('o', 162, osd_raw_cmd_t)
+#define OSD_RAW_DATA _IOWR('o', 163, osd_raw_data_t)
+
#endif