From: Hans Verkuil <hans.verkuil@cisco.com>
Date: Tue, 22 Jul 2014 04:13:07 +0000 (+0200)
Subject: [media] solo6x10: move out of staging into drivers/media/pci.
X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=28cae868cd24;p=linux.git

[media] solo6x10: move out of staging into drivers/media/pci.

Now that the custom motion detection API has been replaced with a
standard API there is no reason anymore to keep it in staging.

So (finally!) move it to drivers/media/pci.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---

diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig
index 53196f1366f30..5c16c9c2203ef 100644
--- a/drivers/media/pci/Kconfig
+++ b/drivers/media/pci/Kconfig
@@ -19,6 +19,7 @@ if MEDIA_ANALOG_TV_SUPPORT
 source "drivers/media/pci/ivtv/Kconfig"
 source "drivers/media/pci/zoran/Kconfig"
 source "drivers/media/pci/saa7146/Kconfig"
+source "drivers/media/pci/solo6x10/Kconfig"
 endif
 
 if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT
diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile
index 35cc57862c01b..e5b53fb569efa 100644
--- a/drivers/media/pci/Makefile
+++ b/drivers/media/pci/Makefile
@@ -24,3 +24,4 @@ obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
 obj-$(CONFIG_VIDEO_SAA7164) += saa7164/
 obj-$(CONFIG_VIDEO_MEYE) += meye/
 obj-$(CONFIG_STA2X11_VIP) += sta2x11/
+obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/
diff --git a/drivers/media/pci/solo6x10/Kconfig b/drivers/media/pci/solo6x10/Kconfig
new file mode 100644
index 0000000000000..d9e06a6bf1ebc
--- /dev/null
+++ b/drivers/media/pci/solo6x10/Kconfig
@@ -0,0 +1,19 @@
+config VIDEO_SOLO6X10
+	tristate "Bluecherry / Softlogic 6x10 capture cards (MPEG-4/H.264)"
+	depends on PCI && VIDEO_DEV && SND && I2C
+	select BITREVERSE
+	select FONT_SUPPORT
+	select FONT_8x16
+	select VIDEOBUF2_DMA_SG
+	select VIDEOBUF2_DMA_CONTIG
+	select SND_PCM
+	select FONT_8x16
+	---help---
+	  This driver supports the Bluecherry H.264 and MPEG-4 hardware
+	  compression capture cards and other Softlogic-based ones.
+
+	  Following cards have been tested:
+	  * Bluecherry BC-H16480A (PCIe, 16 port, H.264)
+	  * Bluecherry BC-H04120A (PCIe, 4 port, H.264)
+	  * Bluecherry BC-H04120A-MPCI (Mini-PCI, 4 port, H.264)
+	  * Bluecherry BC-04120A (PCIe, 4 port, MPEG-4)
diff --git a/drivers/media/pci/solo6x10/Makefile b/drivers/media/pci/solo6x10/Makefile
new file mode 100644
index 0000000000000..f4742266ef7c0
--- /dev/null
+++ b/drivers/media/pci/solo6x10/Makefile
@@ -0,0 +1,5 @@
+solo6x10-y := solo6x10-core.o solo6x10-i2c.o solo6x10-p2m.o solo6x10-v4l2.o \
+		solo6x10-tw28.o solo6x10-gpio.o solo6x10-disp.o solo6x10-enc.o \
+		solo6x10-v4l2-enc.o solo6x10-g723.o solo6x10-eeprom.o
+
+obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10.o
diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c
new file mode 100644
index 0000000000000..172583d736fef
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10-core.c
@@ -0,0 +1,705 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/ktime.h>
+#include <linux/slab.h>
+
+#include "solo6x10.h"
+#include "solo6x10-tw28.h"
+
+MODULE_DESCRIPTION("Softlogic 6x10 MPEG4/H.264/G.723 CODEC V4L2/ALSA Driver");
+MODULE_AUTHOR("Bluecherry <maintainers@bluecherrydvr.com>");
+MODULE_VERSION(SOLO6X10_VERSION);
+MODULE_LICENSE("GPL");
+
+static unsigned video_nr = -1;
+module_param(video_nr, uint, 0644);
+MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)");
+
+static int full_eeprom; /* default is only top 64B */
+module_param(full_eeprom, uint, 0644);
+MODULE_PARM_DESC(full_eeprom, "Allow access to full 128B EEPROM (dangerous)");
+
+
+static void solo_set_time(struct solo_dev *solo_dev)
+{
+	struct timespec ts;
+
+	ktime_get_ts(&ts);
+
+	solo_reg_write(solo_dev, SOLO_TIMER_SEC, ts.tv_sec);
+	solo_reg_write(solo_dev, SOLO_TIMER_USEC, ts.tv_nsec / NSEC_PER_USEC);
+}
+
+static void solo_timer_sync(struct solo_dev *solo_dev)
+{
+	u32 sec, usec;
+	struct timespec ts;
+	long diff;
+
+	if (solo_dev->type != SOLO_DEV_6110)
+		return;
+
+	if (++solo_dev->time_sync < 60)
+		return;
+
+	solo_dev->time_sync = 0;
+
+	sec = solo_reg_read(solo_dev, SOLO_TIMER_SEC);
+	usec = solo_reg_read(solo_dev, SOLO_TIMER_USEC);
+
+	ktime_get_ts(&ts);
+
+	diff = (long)ts.tv_sec - (long)sec;
+	diff = (diff * 1000000)
+		+ ((long)(ts.tv_nsec / NSEC_PER_USEC) - (long)usec);
+
+	if (diff > 1000 || diff < -1000) {
+		solo_set_time(solo_dev);
+	} else if (diff) {
+		long usec_lsb = solo_dev->usec_lsb;
+
+		usec_lsb -= diff / 4;
+		if (usec_lsb < 0)
+			usec_lsb = 0;
+		else if (usec_lsb > 255)
+			usec_lsb = 255;
+
+		solo_dev->usec_lsb = usec_lsb;
+		solo_reg_write(solo_dev, SOLO_TIMER_USEC_LSB,
+			       solo_dev->usec_lsb);
+	}
+}
+
+static irqreturn_t solo_isr(int irq, void *data)
+{
+	struct solo_dev *solo_dev = data;
+	u32 status;
+	int i;
+
+	status = solo_reg_read(solo_dev, SOLO_IRQ_STAT);
+	if (!status)
+		return IRQ_NONE;
+
+	if (status & ~solo_dev->irq_mask) {
+		solo_reg_write(solo_dev, SOLO_IRQ_STAT,
+			       status & ~solo_dev->irq_mask);
+		status &= solo_dev->irq_mask;
+	}
+
+	if (status & SOLO_IRQ_PCI_ERR)
+		solo_p2m_error_isr(solo_dev);
+
+	for (i = 0; i < SOLO_NR_P2M; i++)
+		if (status & SOLO_IRQ_P2M(i))
+			solo_p2m_isr(solo_dev, i);
+
+	if (status & SOLO_IRQ_IIC)
+		solo_i2c_isr(solo_dev);
+
+	if (status & SOLO_IRQ_VIDEO_IN) {
+		solo_video_in_isr(solo_dev);
+		solo_timer_sync(solo_dev);
+	}
+
+	if (status & SOLO_IRQ_ENCODER)
+		solo_enc_v4l2_isr(solo_dev);
+
+	if (status & SOLO_IRQ_G723)
+		solo_g723_isr(solo_dev);
+
+	/* Clear all interrupts handled */
+	solo_reg_write(solo_dev, SOLO_IRQ_STAT, status);
+
+	return IRQ_HANDLED;
+}
+
+static void free_solo_dev(struct solo_dev *solo_dev)
+{
+	struct pci_dev *pdev;
+
+	if (!solo_dev)
+		return;
+
+	if (solo_dev->dev.parent)
+		device_unregister(&solo_dev->dev);
+
+	pdev = solo_dev->pdev;
+
+	/* If we never initialized the PCI device, then nothing else
+	 * below here needs cleanup */
+	if (!pdev) {
+		kfree(solo_dev);
+		return;
+	}
+
+	if (solo_dev->reg_base) {
+		/* Bring down the sub-devices first */
+		solo_g723_exit(solo_dev);
+		solo_enc_v4l2_exit(solo_dev);
+		solo_enc_exit(solo_dev);
+		solo_v4l2_exit(solo_dev);
+		solo_disp_exit(solo_dev);
+		solo_gpio_exit(solo_dev);
+		solo_p2m_exit(solo_dev);
+		solo_i2c_exit(solo_dev);
+
+		/* Now cleanup the PCI device */
+		solo_irq_off(solo_dev, ~0);
+		pci_iounmap(pdev, solo_dev->reg_base);
+		if (pdev->irq)
+			free_irq(pdev->irq, solo_dev);
+	}
+
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	v4l2_device_unregister(&solo_dev->v4l2_dev);
+	pci_set_drvdata(pdev, NULL);
+
+	kfree(solo_dev);
+}
+
+static ssize_t eeprom_store(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct solo_dev *solo_dev =
+		container_of(dev, struct solo_dev, dev);
+	unsigned short *p = (unsigned short *)buf;
+	int i;
+
+	if (count & 0x1)
+		dev_warn(dev, "EEPROM Write not aligned (truncating)\n");
+
+	if (!full_eeprom && count > 64) {
+		dev_warn(dev, "EEPROM Write truncated to 64 bytes\n");
+		count = 64;
+	} else if (full_eeprom && count > 128) {
+		dev_warn(dev, "EEPROM Write truncated to 128 bytes\n");
+		count = 128;
+	}
+
+	solo_eeprom_ewen(solo_dev, 1);
+
+	for (i = full_eeprom ? 0 : 32; i < min((int)(full_eeprom ? 64 : 32),
+					       (int)(count / 2)); i++)
+		solo_eeprom_write(solo_dev, i, cpu_to_be16(p[i]));
+
+	solo_eeprom_ewen(solo_dev, 0);
+
+	return count;
+}
+
+static ssize_t eeprom_show(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct solo_dev *solo_dev =
+		container_of(dev, struct solo_dev, dev);
+	unsigned short *p = (unsigned short *)buf;
+	int count = (full_eeprom ? 128 : 64);
+	int i;
+
+	for (i = (full_eeprom ? 0 : 32); i < (count / 2); i++)
+		p[i] = be16_to_cpu(solo_eeprom_read(solo_dev, i));
+
+	return count;
+}
+
+static ssize_t p2m_timeouts_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct solo_dev *solo_dev =
+		container_of(dev, struct solo_dev, dev);
+
+	return sprintf(buf, "%d\n", solo_dev->p2m_timeouts);
+}
+
+static ssize_t sdram_size_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	struct solo_dev *solo_dev =
+		container_of(dev, struct solo_dev, dev);
+
+	return sprintf(buf, "%dMegs\n", solo_dev->sdram_size >> 20);
+}
+
+static ssize_t tw28xx_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	struct solo_dev *solo_dev =
+		container_of(dev, struct solo_dev, dev);
+
+	return sprintf(buf, "tw2815[%d] tw2864[%d] tw2865[%d]\n",
+		       hweight32(solo_dev->tw2815),
+		       hweight32(solo_dev->tw2864),
+		       hweight32(solo_dev->tw2865));
+}
+
+static ssize_t input_map_show(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	struct solo_dev *solo_dev =
+		container_of(dev, struct solo_dev, dev);
+	unsigned int val;
+	char *out = buf;
+
+	val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_0);
+	out += sprintf(out, "Channel 0   => Input %d\n", val & 0x1f);
+	out += sprintf(out, "Channel 1   => Input %d\n", (val >> 5) & 0x1f);
+	out += sprintf(out, "Channel 2   => Input %d\n", (val >> 10) & 0x1f);
+	out += sprintf(out, "Channel 3   => Input %d\n", (val >> 15) & 0x1f);
+	out += sprintf(out, "Channel 4   => Input %d\n", (val >> 20) & 0x1f);
+	out += sprintf(out, "Channel 5   => Input %d\n", (val >> 25) & 0x1f);
+
+	val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_1);
+	out += sprintf(out, "Channel 6   => Input %d\n", val & 0x1f);
+	out += sprintf(out, "Channel 7   => Input %d\n", (val >> 5) & 0x1f);
+	out += sprintf(out, "Channel 8   => Input %d\n", (val >> 10) & 0x1f);
+	out += sprintf(out, "Channel 9   => Input %d\n", (val >> 15) & 0x1f);
+	out += sprintf(out, "Channel 10  => Input %d\n", (val >> 20) & 0x1f);
+	out += sprintf(out, "Channel 11  => Input %d\n", (val >> 25) & 0x1f);
+
+	val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_2);
+	out += sprintf(out, "Channel 12  => Input %d\n", val & 0x1f);
+	out += sprintf(out, "Channel 13  => Input %d\n", (val >> 5) & 0x1f);
+	out += sprintf(out, "Channel 14  => Input %d\n", (val >> 10) & 0x1f);
+	out += sprintf(out, "Channel 15  => Input %d\n", (val >> 15) & 0x1f);
+	out += sprintf(out, "Spot Output => Input %d\n", (val >> 20) & 0x1f);
+
+	return out - buf;
+}
+
+static ssize_t p2m_timeout_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct solo_dev *solo_dev =
+		container_of(dev, struct solo_dev, dev);
+	unsigned long ms;
+	int ret = kstrtoul(buf, 10, &ms);
+
+	if (ret < 0 || ms > 200)
+		return -EINVAL;
+	solo_dev->p2m_jiffies = msecs_to_jiffies(ms);
+
+	return count;
+}
+
+static ssize_t p2m_timeout_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct solo_dev *solo_dev =
+		container_of(dev, struct solo_dev, dev);
+
+	return sprintf(buf, "%ums\n", jiffies_to_msecs(solo_dev->p2m_jiffies));
+}
+
+static ssize_t intervals_show(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	struct solo_dev *solo_dev =
+		container_of(dev, struct solo_dev, dev);
+	char *out = buf;
+	int fps = solo_dev->fps;
+	int i;
+
+	for (i = 0; i < solo_dev->nr_chans; i++) {
+		out += sprintf(out, "Channel %d: %d/%d (0x%08x)\n",
+			       i, solo_dev->v4l2_enc[i]->interval, fps,
+			       solo_reg_read(solo_dev, SOLO_CAP_CH_INTV(i)));
+	}
+
+	return out - buf;
+}
+
+static ssize_t sdram_offsets_show(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	struct solo_dev *solo_dev =
+		container_of(dev, struct solo_dev, dev);
+	char *out = buf;
+
+	out += sprintf(out, "DISP: 0x%08x @ 0x%08x\n",
+		       SOLO_DISP_EXT_ADDR,
+		       SOLO_DISP_EXT_SIZE);
+
+	out += sprintf(out, "EOSD: 0x%08x @ 0x%08x (0x%08x * %d)\n",
+		       SOLO_EOSD_EXT_ADDR,
+		       SOLO_EOSD_EXT_AREA(solo_dev),
+		       SOLO_EOSD_EXT_SIZE(solo_dev),
+		       SOLO_EOSD_EXT_AREA(solo_dev) /
+		       SOLO_EOSD_EXT_SIZE(solo_dev));
+
+	out += sprintf(out, "MOTI: 0x%08x @ 0x%08x\n",
+		       SOLO_MOTION_EXT_ADDR(solo_dev),
+		       SOLO_MOTION_EXT_SIZE);
+
+	out += sprintf(out, "G723: 0x%08x @ 0x%08x\n",
+		       SOLO_G723_EXT_ADDR(solo_dev),
+		       SOLO_G723_EXT_SIZE);
+
+	out += sprintf(out, "CAPT: 0x%08x @ 0x%08x (0x%08x * %d)\n",
+		       SOLO_CAP_EXT_ADDR(solo_dev),
+		       SOLO_CAP_EXT_SIZE(solo_dev),
+		       SOLO_CAP_PAGE_SIZE,
+		       SOLO_CAP_EXT_SIZE(solo_dev) / SOLO_CAP_PAGE_SIZE);
+
+	out += sprintf(out, "EREF: 0x%08x @ 0x%08x (0x%08x * %d)\n",
+		       SOLO_EREF_EXT_ADDR(solo_dev),
+		       SOLO_EREF_EXT_AREA(solo_dev),
+		       SOLO_EREF_EXT_SIZE,
+		       SOLO_EREF_EXT_AREA(solo_dev) / SOLO_EREF_EXT_SIZE);
+
+	out += sprintf(out, "MPEG: 0x%08x @ 0x%08x\n",
+		       SOLO_MP4E_EXT_ADDR(solo_dev),
+		       SOLO_MP4E_EXT_SIZE(solo_dev));
+
+	out += sprintf(out, "JPEG: 0x%08x @ 0x%08x\n",
+		       SOLO_JPEG_EXT_ADDR(solo_dev),
+		       SOLO_JPEG_EXT_SIZE(solo_dev));
+
+	return out - buf;
+}
+
+static ssize_t sdram_show(struct file *file, struct kobject *kobj,
+			  struct bin_attribute *a, char *buf,
+			  loff_t off, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct solo_dev *solo_dev =
+		container_of(dev, struct solo_dev, dev);
+	const int size = solo_dev->sdram_size;
+
+	if (off >= size)
+		return 0;
+
+	if (off + count > size)
+		count = size - off;
+
+	if (solo_p2m_dma(solo_dev, 0, buf, off, count, 0, 0))
+		return -EIO;
+
+	return count;
+}
+
+static const struct device_attribute solo_dev_attrs[] = {
+	__ATTR(eeprom, 0640, eeprom_show, eeprom_store),
+	__ATTR(p2m_timeout, 0644, p2m_timeout_show, p2m_timeout_store),
+	__ATTR_RO(p2m_timeouts),
+	__ATTR_RO(sdram_size),
+	__ATTR_RO(tw28xx),
+	__ATTR_RO(input_map),
+	__ATTR_RO(intervals),
+	__ATTR_RO(sdram_offsets),
+};
+
+static void solo_device_release(struct device *dev)
+{
+	/* Do nothing */
+}
+
+static int solo_sysfs_init(struct solo_dev *solo_dev)
+{
+	struct bin_attribute *sdram_attr = &solo_dev->sdram_attr;
+	struct device *dev = &solo_dev->dev;
+	const char *driver;
+	int i;
+
+	if (solo_dev->type == SOLO_DEV_6110)
+		driver = "solo6110";
+	else
+		driver = "solo6010";
+
+	dev->release = solo_device_release;
+	dev->parent = &solo_dev->pdev->dev;
+	set_dev_node(dev, dev_to_node(&solo_dev->pdev->dev));
+	dev_set_name(dev, "%s-%d-%d", driver, solo_dev->vfd->num,
+		     solo_dev->nr_chans);
+
+	if (device_register(dev)) {
+		dev->parent = NULL;
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(solo_dev_attrs); i++) {
+		if (device_create_file(dev, &solo_dev_attrs[i])) {
+			device_unregister(dev);
+			return -ENOMEM;
+		}
+	}
+
+	sysfs_attr_init(&sdram_attr->attr);
+	sdram_attr->attr.name = "sdram";
+	sdram_attr->attr.mode = 0440;
+	sdram_attr->read = sdram_show;
+	sdram_attr->size = solo_dev->sdram_size;
+
+	if (device_create_bin_file(dev, sdram_attr)) {
+		device_unregister(dev);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int solo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct solo_dev *solo_dev;
+	int ret;
+	u8 chip_id;
+
+	solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL);
+	if (solo_dev == NULL)
+		return -ENOMEM;
+
+	if (id->driver_data == SOLO_DEV_6010)
+		dev_info(&pdev->dev, "Probing Softlogic 6010\n");
+	else
+		dev_info(&pdev->dev, "Probing Softlogic 6110\n");
+
+	solo_dev->type = id->driver_data;
+	solo_dev->pdev = pdev;
+	spin_lock_init(&solo_dev->reg_io_lock);
+	ret = v4l2_device_register(&pdev->dev, &solo_dev->v4l2_dev);
+	if (ret)
+		goto fail_probe;
+
+	/* Only for during init */
+	solo_dev->p2m_jiffies = msecs_to_jiffies(100);
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		goto fail_probe;
+
+	pci_set_master(pdev);
+
+	/* RETRY/TRDY Timeout disabled */
+	pci_write_config_byte(pdev, 0x40, 0x00);
+	pci_write_config_byte(pdev, 0x41, 0x00);
+
+	ret = pci_request_regions(pdev, SOLO6X10_NAME);
+	if (ret)
+		goto fail_probe;
+
+	solo_dev->reg_base = pci_ioremap_bar(pdev, 0);
+	if (solo_dev->reg_base == NULL) {
+		ret = -ENOMEM;
+		goto fail_probe;
+	}
+
+	chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) &
+				SOLO_CHIP_ID_MASK;
+	switch (chip_id) {
+	case 7:
+		solo_dev->nr_chans = 16;
+		solo_dev->nr_ext = 5;
+		break;
+	case 6:
+		solo_dev->nr_chans = 8;
+		solo_dev->nr_ext = 2;
+		break;
+	default:
+		dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, assuming 4 ch\n",
+			 chip_id);
+	case 5:
+		solo_dev->nr_chans = 4;
+		solo_dev->nr_ext = 1;
+	}
+
+	/* Disable all interrupts to start */
+	solo_irq_off(solo_dev, ~0);
+
+	/* Initial global settings */
+	if (solo_dev->type == SOLO_DEV_6010) {
+		solo_dev->clock_mhz = 108;
+		solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT
+			| SOLO_SYS_CFG_INPUTDIV(25)
+			| SOLO_SYS_CFG_FEEDBACKDIV(solo_dev->clock_mhz * 2 - 2)
+			| SOLO_SYS_CFG_OUTDIV(3);
+		solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config);
+	} else {
+		u32 divq, divf;
+
+		solo_dev->clock_mhz = 135;
+
+		if (solo_dev->clock_mhz < 125) {
+			divq = 3;
+			divf = (solo_dev->clock_mhz * 4) / 3 - 1;
+		} else {
+			divq = 2;
+			divf = (solo_dev->clock_mhz * 2) / 3 - 1;
+		}
+
+		solo_reg_write(solo_dev, SOLO_PLL_CONFIG,
+			       (1 << 20) | /* PLL_RANGE */
+			       (8 << 15) | /* PLL_DIVR  */
+			       (divq << 12) |
+			       (divf <<  4) |
+			       (1 <<  1)   /* PLL_FSEN */);
+
+		solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT;
+	}
+
+	solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config);
+	solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM,
+		       solo_dev->clock_mhz - 1);
+
+	/* PLL locking time of 1ms */
+	mdelay(1);
+
+	ret = request_irq(pdev->irq, solo_isr, IRQF_SHARED, SOLO6X10_NAME,
+			  solo_dev);
+	if (ret)
+		goto fail_probe;
+
+	/* Handle this from the start */
+	solo_irq_on(solo_dev, SOLO_IRQ_PCI_ERR);
+
+	ret = solo_i2c_init(solo_dev);
+	if (ret)
+		goto fail_probe;
+
+	/* Setup the DMA engine */
+	solo_reg_write(solo_dev, SOLO_DMA_CTRL,
+		       SOLO_DMA_CTRL_REFRESH_CYCLE(1) |
+		       SOLO_DMA_CTRL_SDRAM_SIZE(2) |
+		       SOLO_DMA_CTRL_SDRAM_CLK_INVERT |
+		       SOLO_DMA_CTRL_READ_CLK_SELECT |
+		       SOLO_DMA_CTRL_LATENCY(1));
+
+	/* Undocumented crap */
+	solo_reg_write(solo_dev, SOLO_DMA_CTRL1,
+		       solo_dev->type == SOLO_DEV_6010 ? 0x100 : 0x300);
+
+	if (solo_dev->type != SOLO_DEV_6010) {
+		solo_dev->usec_lsb = 0x3f;
+		solo_set_time(solo_dev);
+	}
+
+	/* Disable watchdog */
+	solo_reg_write(solo_dev, SOLO_WATCHDOG, 0);
+
+	/* Initialize sub components */
+
+	ret = solo_p2m_init(solo_dev);
+	if (ret)
+		goto fail_probe;
+
+	ret = solo_disp_init(solo_dev);
+	if (ret)
+		goto fail_probe;
+
+	ret = solo_gpio_init(solo_dev);
+	if (ret)
+		goto fail_probe;
+
+	ret = solo_tw28_init(solo_dev);
+	if (ret)
+		goto fail_probe;
+
+	ret = solo_v4l2_init(solo_dev, video_nr);
+	if (ret)
+		goto fail_probe;
+
+	ret = solo_enc_init(solo_dev);
+	if (ret)
+		goto fail_probe;
+
+	ret = solo_enc_v4l2_init(solo_dev, video_nr);
+	if (ret)
+		goto fail_probe;
+
+	ret = solo_g723_init(solo_dev);
+	if (ret)
+		goto fail_probe;
+
+	ret = solo_sysfs_init(solo_dev);
+	if (ret)
+		goto fail_probe;
+
+	/* Now that init is over, set this lower */
+	solo_dev->p2m_jiffies = msecs_to_jiffies(20);
+
+	return 0;
+
+fail_probe:
+	free_solo_dev(solo_dev);
+	return ret;
+}
+
+static void solo_pci_remove(struct pci_dev *pdev)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+	struct solo_dev *solo_dev = container_of(v4l2_dev, struct solo_dev, v4l2_dev);
+
+	free_solo_dev(solo_dev);
+}
+
+static const struct pci_device_id solo_id_table[] = {
+	/* 6010 based cards */
+	{ PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010),
+	  .driver_data = SOLO_DEV_6010 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4),
+	  .driver_data = SOLO_DEV_6010 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9),
+	  .driver_data = SOLO_DEV_6010 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16),
+	  .driver_data = SOLO_DEV_6010 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4),
+	  .driver_data = SOLO_DEV_6010 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9),
+	  .driver_data = SOLO_DEV_6010 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16),
+	  .driver_data = SOLO_DEV_6010 },
+	/* 6110 based cards */
+	{ PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6110),
+	  .driver_data = SOLO_DEV_6110 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4),
+	  .driver_data = SOLO_DEV_6110 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8),
+	  .driver_data = SOLO_DEV_6110 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16),
+	  .driver_data = SOLO_DEV_6110 },
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, solo_id_table);
+
+static struct pci_driver solo_pci_driver = {
+	.name = SOLO6X10_NAME,
+	.id_table = solo_id_table,
+	.probe = solo_pci_probe,
+	.remove = solo_pci_remove,
+};
+
+module_pci_driver(solo_pci_driver);
diff --git a/drivers/media/pci/solo6x10/solo6x10-disp.c b/drivers/media/pci/solo6x10/solo6x10-disp.c
new file mode 100644
index 0000000000000..ed88ab4455a55
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10-disp.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ioctl.h>
+
+#include "solo6x10.h"
+
+#define SOLO_VCLK_DELAY			3
+#define SOLO_PROGRESSIVE_VSIZE		1024
+
+#define SOLO_MOT_THRESH_W		64
+#define SOLO_MOT_THRESH_H		64
+#define SOLO_MOT_THRESH_SIZE		8192
+#define SOLO_MOT_THRESH_REAL		(SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H)
+#define SOLO_MOT_FLAG_SIZE		1024
+#define SOLO_MOT_FLAG_AREA		(SOLO_MOT_FLAG_SIZE * 16)
+
+static void solo_vin_config(struct solo_dev *solo_dev)
+{
+	solo_dev->vin_hstart = 8;
+	solo_dev->vin_vstart = 2;
+
+	solo_reg_write(solo_dev, SOLO_SYS_VCLK,
+		       SOLO_VCLK_SELECT(2) |
+		       SOLO_VCLK_VIN1415_DELAY(SOLO_VCLK_DELAY) |
+		       SOLO_VCLK_VIN1213_DELAY(SOLO_VCLK_DELAY) |
+		       SOLO_VCLK_VIN1011_DELAY(SOLO_VCLK_DELAY) |
+		       SOLO_VCLK_VIN0809_DELAY(SOLO_VCLK_DELAY) |
+		       SOLO_VCLK_VIN0607_DELAY(SOLO_VCLK_DELAY) |
+		       SOLO_VCLK_VIN0405_DELAY(SOLO_VCLK_DELAY) |
+		       SOLO_VCLK_VIN0203_DELAY(SOLO_VCLK_DELAY) |
+		       SOLO_VCLK_VIN0001_DELAY(SOLO_VCLK_DELAY));
+
+	solo_reg_write(solo_dev, SOLO_VI_ACT_I_P,
+		       SOLO_VI_H_START(solo_dev->vin_hstart) |
+		       SOLO_VI_V_START(solo_dev->vin_vstart) |
+		       SOLO_VI_V_STOP(solo_dev->vin_vstart +
+				      solo_dev->video_vsize));
+
+	solo_reg_write(solo_dev, SOLO_VI_ACT_I_S,
+		       SOLO_VI_H_START(solo_dev->vout_hstart) |
+		       SOLO_VI_V_START(solo_dev->vout_vstart) |
+		       SOLO_VI_V_STOP(solo_dev->vout_vstart +
+				      solo_dev->video_vsize));
+
+	solo_reg_write(solo_dev, SOLO_VI_ACT_P,
+		       SOLO_VI_H_START(0) |
+		       SOLO_VI_V_START(1) |
+		       SOLO_VI_V_STOP(SOLO_PROGRESSIVE_VSIZE));
+
+	solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT,
+		       SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0));
+
+	/* On 6110, initialize mozaic darkness stength */
+	if (solo_dev->type == SOLO_DEV_6010)
+		solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0);
+	else
+		solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 16 << 22);
+
+	solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2);
+
+	if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
+		solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
+			       SOLO_VI_PB_USER_MODE);
+		solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
+			       SOLO_VI_PB_HSIZE(858) | SOLO_VI_PB_VSIZE(246));
+		solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
+			       SOLO_VI_PB_VSTART(4) |
+			       SOLO_VI_PB_VSTOP(4 + 240));
+	} else {
+		solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
+			       SOLO_VI_PB_USER_MODE | SOLO_VI_PB_PAL);
+		solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
+			       SOLO_VI_PB_HSIZE(864) | SOLO_VI_PB_VSIZE(294));
+		solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
+			       SOLO_VI_PB_VSTART(4) |
+			       SOLO_VI_PB_VSTOP(4 + 288));
+	}
+	solo_reg_write(solo_dev, SOLO_VI_PB_ACT_H, SOLO_VI_PB_HSTART(16) |
+		       SOLO_VI_PB_HSTOP(16 + 720));
+}
+
+static void solo_vout_config_cursor(struct solo_dev *dev)
+{
+	int i;
+
+	/* Load (blank) cursor bitmap mask (2bpp) */
+	for (i = 0; i < 20; i++)
+		solo_reg_write(dev, SOLO_VO_CURSOR_MASK(i), 0);
+
+	solo_reg_write(dev, SOLO_VO_CURSOR_POS, 0);
+
+	solo_reg_write(dev, SOLO_VO_CURSOR_CLR,
+		       (0x80 << 24) | (0x80 << 16) | (0x10 << 8) | 0x80);
+	solo_reg_write(dev, SOLO_VO_CURSOR_CLR2, (0xe0 << 8) | 0x80);
+}
+
+static void solo_vout_config(struct solo_dev *solo_dev)
+{
+	solo_dev->vout_hstart = 6;
+	solo_dev->vout_vstart = 8;
+
+	solo_reg_write(solo_dev, SOLO_VO_FMT_ENC,
+		       solo_dev->video_type |
+		       SOLO_VO_USER_COLOR_SET_NAV |
+		       SOLO_VO_USER_COLOR_SET_NAH |
+		       SOLO_VO_NA_COLOR_Y(0) |
+		       SOLO_VO_NA_COLOR_CB(0) |
+		       SOLO_VO_NA_COLOR_CR(0));
+
+	solo_reg_write(solo_dev, SOLO_VO_ACT_H,
+		       SOLO_VO_H_START(solo_dev->vout_hstart) |
+		       SOLO_VO_H_STOP(solo_dev->vout_hstart +
+				      solo_dev->video_hsize));
+
+	solo_reg_write(solo_dev, SOLO_VO_ACT_V,
+		       SOLO_VO_V_START(solo_dev->vout_vstart) |
+		       SOLO_VO_V_STOP(solo_dev->vout_vstart +
+				      solo_dev->video_vsize));
+
+	solo_reg_write(solo_dev, SOLO_VO_RANGE_HV,
+		       SOLO_VO_H_LEN(solo_dev->video_hsize) |
+		       SOLO_VO_V_LEN(solo_dev->video_vsize));
+
+	/* Border & background colors */
+	solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR,
+		       (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88);
+	solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR,
+		       (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f);
+	solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR,
+		       (16 << 24) | (128 << 16) | (16 << 8) | 128);
+
+	solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
+
+	solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 0);
+
+	solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
+	solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
+
+	solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON |
+		       SOLO_VO_DISP_ERASE_COUNT(8) |
+		       SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR));
+
+
+	solo_vout_config_cursor(solo_dev);
+
+	/* Enable channels we support */
+	solo_reg_write(solo_dev, SOLO_VI_CH_ENA,
+		       (1 << solo_dev->nr_chans) - 1);
+}
+
+static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off,
+			       u16 val, int reg_size)
+{
+	u16 *buf;
+	const int n = 64, size = n * sizeof(*buf);
+	int i, ret = 0;
+
+	buf = kmalloc(size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (i = 0; i < n; i++)
+		buf[i] = cpu_to_le16(val);
+
+	for (i = 0; i < reg_size; i += size) {
+		ret = solo_p2m_dma(solo_dev, 1, buf,
+				   SOLO_MOTION_EXT_ADDR(solo_dev) + off + i,
+				   size, 0, 0);
+
+		if (ret)
+			break;
+	}
+
+	kfree(buf);
+	return ret;
+}
+
+int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val)
+{
+	if (ch > solo_dev->nr_chans)
+		return -EINVAL;
+
+	return solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
+				   (ch * SOLO_MOT_THRESH_SIZE * 2),
+				   val, SOLO_MOT_THRESH_SIZE);
+}
+
+int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
+		const u16 *thresholds)
+{
+	const unsigned size = sizeof(u16) * 64;
+	u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2;
+	u16 *buf;
+	int x, y;
+	int ret = 0;
+
+	buf = kzalloc(size, GFP_KERNEL);
+	for (y = 0; y < SOLO_MOTION_SZ; y++) {
+		for (x = 0; x < SOLO_MOTION_SZ; x++)
+			buf[x] = cpu_to_le16(thresholds[y * SOLO_MOTION_SZ + x]);
+		ret |= solo_p2m_dma(solo_dev, 1, buf,
+			SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * size,
+			size, 0, 0);
+	}
+	kfree(buf);
+	return ret;
+}
+
+/* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k
+ * threshold and working table for each channel. Atleast that's what the
+ * spec says. However, this code (taken from rdk) has some mystery 8k
+ * block right after the flag area, before the first thresh table. */
+static void solo_motion_config(struct solo_dev *solo_dev)
+{
+	int i;
+
+	for (i = 0; i < solo_dev->nr_chans; i++) {
+		/* Clear motion flag area */
+		solo_dma_vin_region(solo_dev, i * SOLO_MOT_FLAG_SIZE, 0x0000,
+				    SOLO_MOT_FLAG_SIZE);
+
+		/* Clear working cache table */
+		solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
+				    (i * SOLO_MOT_THRESH_SIZE * 2) +
+				    SOLO_MOT_THRESH_SIZE, 0x0000,
+				    SOLO_MOT_THRESH_SIZE);
+
+		/* Set default threshold table */
+		solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH);
+	}
+
+	/* Default motion settings */
+	solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) |
+		       (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
+	solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL,
+		       SOLO_VI_MOTION_FRAME_COUNT(3) |
+		       SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16)
+		       /* | SOLO_VI_MOTION_INTR_START_STOP */
+		       | SOLO_VI_MOTION_SAMPLE_COUNT(10));
+
+	solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
+	solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
+}
+
+int solo_disp_init(struct solo_dev *solo_dev)
+{
+	int i;
+
+	solo_dev->video_hsize = 704;
+	if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
+		solo_dev->video_vsize = 240;
+		solo_dev->fps = 30;
+	} else {
+		solo_dev->video_vsize = 288;
+		solo_dev->fps = 25;
+	}
+
+	solo_vin_config(solo_dev);
+	solo_motion_config(solo_dev);
+	solo_vout_config(solo_dev);
+
+	for (i = 0; i < solo_dev->nr_chans; i++)
+		solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1);
+
+	return 0;
+}
+
+void solo_disp_exit(struct solo_dev *solo_dev)
+{
+	int i;
+
+	solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0);
+	solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
+	solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
+
+	for (i = 0; i < solo_dev->nr_chans; i++) {
+		solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(i), 0);
+		solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(i), 0);
+		solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 0);
+	}
+
+	/* Set default border */
+	for (i = 0; i < 5; i++)
+		solo_reg_write(solo_dev, SOLO_VO_BORDER_X(i), 0);
+
+	for (i = 0; i < 5; i++)
+		solo_reg_write(solo_dev, SOLO_VO_BORDER_Y(i), 0);
+
+	solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_MASK, 0);
+	solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_MASK, 0);
+
+	solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0);
+	solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0);
+	solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0);
+
+	solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0);
+	solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0);
+	solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0);
+}
diff --git a/drivers/media/pci/solo6x10/solo6x10-eeprom.c b/drivers/media/pci/solo6x10/solo6x10-eeprom.c
new file mode 100644
index 0000000000000..af40b3aba4100
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10-eeprom.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include "solo6x10.h"
+
+/* Control */
+#define EE_SHIFT_CLK	0x04
+#define EE_CS		0x08
+#define EE_DATA_WRITE	0x02
+#define EE_DATA_READ	0x01
+#define EE_ENB		(0x80 | EE_CS)
+
+#define eeprom_delay()	udelay(100)
+#if 0
+#define eeprom_delay()	solo_reg_read(solo_dev, SOLO_EEPROM_CTRL)
+#define eeprom_delay()	({				\
+	int i, ret;					\
+	udelay(100);					\
+	for (i = ret = 0; i < 1000 && !ret; i++)	\
+		ret = solo_eeprom_reg_read(solo_dev);	\
+})
+#endif
+#define ADDR_LEN	6
+
+/* Commands */
+#define EE_EWEN_CMD	4
+#define EE_EWDS_CMD	4
+#define EE_WRITE_CMD	5
+#define EE_READ_CMD	6
+#define EE_ERASE_CMD	7
+
+static unsigned int solo_eeprom_reg_read(struct solo_dev *solo_dev)
+{
+	return solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) & EE_DATA_READ;
+}
+
+static void solo_eeprom_reg_write(struct solo_dev *solo_dev, u32 data)
+{
+	solo_reg_write(solo_dev, SOLO_EEPROM_CTRL, data);
+	eeprom_delay();
+}
+
+static void solo_eeprom_cmd(struct solo_dev *solo_dev, int cmd)
+{
+	int i;
+
+	solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ACCESS_EN);
+	solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
+
+	for (i = 4 + ADDR_LEN; i >= 0; i--) {
+		int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+
+		solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | dataval);
+		solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
+				      EE_SHIFT_CLK | dataval);
+	}
+
+	solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
+}
+
+unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en)
+{
+	int ewen_cmd = (w_en ? 0x3f : 0) | (EE_EWEN_CMD << ADDR_LEN);
+	unsigned int retval = 0;
+	int i;
+
+	solo_eeprom_cmd(solo_dev, ewen_cmd);
+
+	for (i = 0; i < 16; i++) {
+		solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
+				      EE_SHIFT_CLK);
+		retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
+		solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
+		retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
+	}
+
+	solo_eeprom_reg_write(solo_dev, ~EE_CS);
+	retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
+
+	return retval;
+}
+
+unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc)
+{
+	int read_cmd = loc | (EE_READ_CMD << ADDR_LEN);
+	unsigned short retval = 0;
+	int i;
+
+	solo_eeprom_cmd(solo_dev, read_cmd);
+
+	for (i = 0; i < 16; i++) {
+		solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
+				      EE_SHIFT_CLK);
+		retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
+		solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
+	}
+
+	solo_eeprom_reg_write(solo_dev, ~EE_CS);
+
+	return retval;
+}
+
+int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
+		      unsigned short data)
+{
+	int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN);
+	unsigned int retval;
+	int i;
+
+	solo_eeprom_cmd(solo_dev, write_cmd);
+
+	for (i = 15; i >= 0; i--) {
+		unsigned int dataval = (data >> i) & 1;
+
+		solo_eeprom_reg_write(solo_dev, EE_ENB);
+		solo_eeprom_reg_write(solo_dev,
+				      EE_ENB | (dataval << 1) | EE_SHIFT_CLK);
+	}
+
+	solo_eeprom_reg_write(solo_dev, EE_ENB);
+	solo_eeprom_reg_write(solo_dev, ~EE_CS);
+	solo_eeprom_reg_write(solo_dev, EE_ENB);
+
+	for (i = retval = 0; i < 10000 && !retval; i++)
+		retval = solo_eeprom_reg_read(solo_dev);
+
+	solo_eeprom_reg_write(solo_dev, ~EE_CS);
+
+	return !retval;
+}
diff --git a/drivers/media/pci/solo6x10/solo6x10-enc.c b/drivers/media/pci/solo6x10/solo6x10-enc.c
new file mode 100644
index 0000000000000..d19c0aef5abc1
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10-enc.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/font.h>
+#include <linux/bitrev.h>
+#include <linux/slab.h>
+
+#include "solo6x10.h"
+
+#define VI_PROG_HSIZE			(1280 - 16)
+#define VI_PROG_VSIZE			(1024 - 16)
+
+#define IRQ_LEVEL			2
+
+static void solo_capture_config(struct solo_dev *solo_dev)
+{
+	unsigned long height;
+	unsigned long width;
+	void *buf;
+	int i;
+
+	solo_reg_write(solo_dev, SOLO_CAP_BASE,
+		       SOLO_CAP_MAX_PAGE((SOLO_CAP_EXT_SIZE(solo_dev)
+					  - SOLO_CAP_PAGE_SIZE) >> 16)
+		       | SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16));
+
+	/* XXX: Undocumented bits at b17 and b24 */
+	if (solo_dev->type == SOLO_DEV_6110) {
+		/* NOTE: Ref driver has (62 << 24) here as well, but it causes
+		 * wacked out frame timing on 4-port 6110. */
+		solo_reg_write(solo_dev, SOLO_CAP_BTW,
+			       (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) |
+			       SOLO_CAP_MAX_BANDWIDTH(36));
+	} else {
+		solo_reg_write(solo_dev, SOLO_CAP_BTW,
+			       (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) |
+			       SOLO_CAP_MAX_BANDWIDTH(32));
+	}
+
+	/* Set scale 1, 9 dimension */
+	width = solo_dev->video_hsize;
+	height = solo_dev->video_vsize;
+	solo_reg_write(solo_dev, SOLO_DIM_SCALE1,
+		       SOLO_DIM_H_MB_NUM(width / 16) |
+		       SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
+		       SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+	/* Set scale 2, 10 dimension */
+	width = solo_dev->video_hsize / 2;
+	height = solo_dev->video_vsize;
+	solo_reg_write(solo_dev, SOLO_DIM_SCALE2,
+		       SOLO_DIM_H_MB_NUM(width / 16) |
+		       SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
+		       SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+	/* Set scale 3, 11 dimension */
+	width = solo_dev->video_hsize / 2;
+	height = solo_dev->video_vsize / 2;
+	solo_reg_write(solo_dev, SOLO_DIM_SCALE3,
+		       SOLO_DIM_H_MB_NUM(width / 16) |
+		       SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
+		       SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+	/* Set scale 4, 12 dimension */
+	width = solo_dev->video_hsize / 3;
+	height = solo_dev->video_vsize / 3;
+	solo_reg_write(solo_dev, SOLO_DIM_SCALE4,
+		       SOLO_DIM_H_MB_NUM(width / 16) |
+		       SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
+		       SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+	/* Set scale 5, 13 dimension */
+	width = solo_dev->video_hsize / 4;
+	height = solo_dev->video_vsize / 2;
+	solo_reg_write(solo_dev, SOLO_DIM_SCALE5,
+		       SOLO_DIM_H_MB_NUM(width / 16) |
+		       SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
+		       SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+	/* Progressive */
+	width = VI_PROG_HSIZE;
+	height = VI_PROG_VSIZE;
+	solo_reg_write(solo_dev, SOLO_DIM_PROG,
+		       SOLO_DIM_H_MB_NUM(width / 16) |
+		       SOLO_DIM_V_MB_NUM_FRAME(height / 16) |
+		       SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+	/* Clear OSD */
+	solo_reg_write(solo_dev, SOLO_VE_OSD_CH, 0);
+	solo_reg_write(solo_dev, SOLO_VE_OSD_BASE, SOLO_EOSD_EXT_ADDR >> 16);
+	solo_reg_write(solo_dev, SOLO_VE_OSD_CLR,
+		       0xF0 << 16 | 0x80 << 8 | 0x80);
+
+	if (solo_dev->type == SOLO_DEV_6010)
+		solo_reg_write(solo_dev, SOLO_VE_OSD_OPT,
+			       SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW);
+	else
+		solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, SOLO_VE_OSD_V_DOUBLE
+			       | SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW);
+
+	/* Clear OSG buffer */
+	buf = kzalloc(SOLO_EOSD_EXT_SIZE(solo_dev), GFP_KERNEL);
+	if (!buf)
+		return;
+
+	for (i = 0; i < solo_dev->nr_chans; i++) {
+		solo_p2m_dma(solo_dev, 1, buf,
+			     SOLO_EOSD_EXT_ADDR +
+			     (SOLO_EOSD_EXT_SIZE(solo_dev) * i),
+			     SOLO_EOSD_EXT_SIZE(solo_dev), 0, 0);
+	}
+	kfree(buf);
+}
+
+#define SOLO_OSD_WRITE_SIZE (16 * OSD_TEXT_MAX)
+
+/* Should be called with enable_lock held */
+int solo_osd_print(struct solo_enc_dev *solo_enc)
+{
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+	unsigned char *str = solo_enc->osd_text;
+	u8 *buf = solo_enc->osd_buf;
+	u32 reg;
+	const struct font_desc *vga = find_font("VGA8x16");
+	const unsigned char *vga_data;
+	int i, j;
+
+	if (WARN_ON_ONCE(!vga))
+		return -ENODEV;
+
+	reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH);
+	if (!*str) {
+		/* Disable OSD on this channel */
+		reg &= ~(1 << solo_enc->ch);
+		goto out;
+	}
+
+	memset(buf, 0, SOLO_OSD_WRITE_SIZE);
+	vga_data = (const unsigned char *)vga->data;
+
+	for (i = 0; *str; i++, str++) {
+		for (j = 0; j < 16; j++) {
+			buf[(j << 1) | (i & 1) | ((i & ~1) << 4)] =
+			    bitrev8(vga_data[(*str << 4) | j]);
+		}
+	}
+
+	solo_p2m_dma(solo_dev, 1, buf,
+		     SOLO_EOSD_EXT_ADDR_CHAN(solo_dev, solo_enc->ch),
+		     SOLO_OSD_WRITE_SIZE, 0, 0);
+
+	/* Enable OSD on this channel */
+	reg |= (1 << solo_enc->ch);
+
+out:
+	solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
+	return 0;
+}
+
+/**
+ * Set channel Quality Profile (0-3).
+ */
+void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch,
+		    unsigned int qp)
+{
+	unsigned long flags;
+	unsigned int idx, reg;
+
+	if ((ch > 31) || (qp > 3))
+		return;
+
+	if (solo_dev->type == SOLO_DEV_6010)
+		return;
+
+	if (ch < 16) {
+		idx = 0;
+		reg = SOLO_VE_JPEG_QP_CH_L;
+	} else {
+		ch -= 16;
+		idx = 1;
+		reg = SOLO_VE_JPEG_QP_CH_H;
+	}
+	ch *= 2;
+
+	spin_lock_irqsave(&solo_dev->jpeg_qp_lock, flags);
+
+	solo_dev->jpeg_qp[idx] &= ~(3 << ch);
+	solo_dev->jpeg_qp[idx] |= (qp & 3) << ch;
+
+	solo_reg_write(solo_dev, reg, solo_dev->jpeg_qp[idx]);
+
+	spin_unlock_irqrestore(&solo_dev->jpeg_qp_lock, flags);
+}
+
+int solo_g_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch)
+{
+	int idx;
+
+	if (solo_dev->type == SOLO_DEV_6010)
+		return 2;
+
+	if (WARN_ON_ONCE(ch > 31))
+		return 2;
+
+	if (ch < 16) {
+		idx = 0;
+	} else {
+		ch -= 16;
+		idx = 1;
+	}
+	ch *= 2;
+
+	return (solo_dev->jpeg_qp[idx] >> ch) & 3;
+}
+
+#define SOLO_QP_INIT 0xaaaaaaaa
+
+static void solo_jpeg_config(struct solo_dev *solo_dev)
+{
+	if (solo_dev->type == SOLO_DEV_6010) {
+		solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL,
+			       (2 << 24) | (2 << 16) | (2 << 8) | 2);
+	} else {
+		solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL,
+			       (4 << 24) | (3 << 16) | (2 << 8) | 1);
+	}
+
+	spin_lock_init(&solo_dev->jpeg_qp_lock);
+
+	/* Initialize Quality Profile for all channels */
+	solo_dev->jpeg_qp[0] = solo_dev->jpeg_qp[1] = SOLO_QP_INIT;
+	solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, SOLO_QP_INIT);
+	solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, SOLO_QP_INIT);
+
+	solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG,
+		(SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) |
+		((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff));
+	solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff);
+	if (solo_dev->type == SOLO_DEV_6110) {
+		solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG1,
+			       (0 << 16) | (30 << 8) | 60);
+	}
+}
+
+static void solo_mp4e_config(struct solo_dev *solo_dev)
+{
+	int i;
+	u32 cfg;
+
+	solo_reg_write(solo_dev, SOLO_VE_CFG0,
+		       SOLO_VE_INTR_CTRL(IRQ_LEVEL) |
+		       SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) |
+		       SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16));
+
+
+	cfg = SOLO_VE_BYTE_ALIGN(2) | SOLO_VE_INSERT_INDEX
+		| SOLO_VE_MOTION_MODE(0);
+	if (solo_dev->type != SOLO_DEV_6010) {
+		cfg |= SOLO_VE_MPEG_SIZE_H(
+			(SOLO_MP4E_EXT_SIZE(solo_dev) >> 24) & 0x0f);
+		cfg |= SOLO_VE_JPEG_SIZE_H(
+			(SOLO_JPEG_EXT_SIZE(solo_dev) >> 24) & 0x0f);
+	}
+	solo_reg_write(solo_dev, SOLO_VE_CFG1, cfg);
+
+	solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0);
+	solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0);
+	solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0);
+	if (solo_dev->type == SOLO_DEV_6110)
+		solo_reg_write(solo_dev, SOLO_VE_WMRK_ENABLE, 0);
+	solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0);
+	solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0);
+
+	solo_reg_write(solo_dev, SOLO_VE_ATTR,
+		       SOLO_VE_LITTLE_ENDIAN |
+		       SOLO_COMP_ATTR_FCODE(1) |
+		       SOLO_COMP_TIME_INC(0) |
+		       SOLO_COMP_TIME_WIDTH(15) |
+		       SOLO_DCT_INTERVAL(solo_dev->type == SOLO_DEV_6010 ? 9 : 10));
+
+	for (i = 0; i < solo_dev->nr_chans; i++) {
+		solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i),
+			       (SOLO_EREF_EXT_ADDR(solo_dev) +
+			       (i * SOLO_EREF_EXT_SIZE)) >> 16);
+		solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE_E(i),
+			       (SOLO_EREF_EXT_ADDR(solo_dev) +
+			       ((i + 16) * SOLO_EREF_EXT_SIZE)) >> 16);
+	}
+
+	if (solo_dev->type == SOLO_DEV_6110) {
+		solo_reg_write(solo_dev, SOLO_VE_COMPT_MOT, 0x00040008);
+	} else {
+		for (i = 0; i < solo_dev->nr_chans; i++)
+			solo_reg_write(solo_dev, SOLO_VE_CH_MOT(i), 0x100);
+	}
+}
+
+int solo_enc_init(struct solo_dev *solo_dev)
+{
+	int i;
+
+	solo_capture_config(solo_dev);
+	solo_mp4e_config(solo_dev);
+	solo_jpeg_config(solo_dev);
+
+	for (i = 0; i < solo_dev->nr_chans; i++) {
+		solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
+		solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
+	}
+
+	return 0;
+}
+
+void solo_enc_exit(struct solo_dev *solo_dev)
+{
+	int i;
+
+	for (i = 0; i < solo_dev->nr_chans; i++) {
+		solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
+		solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
+	}
+}
diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c
new file mode 100644
index 0000000000000..c7141f2e63bdb
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10-g723.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/mempool.h>
+#include <linux/poll.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/control.h>
+
+#include "solo6x10.h"
+#include "solo6x10-tw28.h"
+
+#define G723_FDMA_PAGES		32
+#define G723_PERIOD_BYTES	48
+#define G723_PERIOD_BLOCK	1024
+#define G723_FRAMES_PER_PAGE	48
+
+/* Sets up channels 16-19 for decoding and 0-15 for encoding */
+#define OUTMODE_MASK		0x300
+
+#define SAMPLERATE		8000
+#define BITRATE			25
+
+/* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page
+ * is broken down to 20 * 48 byte regions (one for each channel possible)
+ * with the rest of the page being dummy data. */
+#define G723_MAX_BUFFER		(G723_PERIOD_BYTES * PERIODS_MAX)
+#define G723_INTR_ORDER		4 /* 0 - 4 */
+#define PERIODS_MIN		(1 << G723_INTR_ORDER)
+#define PERIODS_MAX		G723_FDMA_PAGES
+
+struct solo_snd_pcm {
+	int				on;
+	spinlock_t			lock;
+	struct solo_dev		*solo_dev;
+	unsigned char			*g723_buf;
+	dma_addr_t			g723_dma;
+};
+
+static void solo_g723_config(struct solo_dev *solo_dev)
+{
+	int clk_div;
+
+	clk_div = (solo_dev->clock_mhz * 1000000)
+		/ (SAMPLERATE * (BITRATE * 2) * 2);
+
+	solo_reg_write(solo_dev, SOLO_AUDIO_SAMPLE,
+		       SOLO_AUDIO_BITRATE(BITRATE)
+		       | SOLO_AUDIO_CLK_DIV(clk_div));
+
+	solo_reg_write(solo_dev, SOLO_AUDIO_FDMA_INTR,
+		       SOLO_AUDIO_FDMA_INTERVAL(1)
+		       | SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER)
+		       | SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16));
+
+	solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL,
+		       SOLO_AUDIO_ENABLE
+		       | SOLO_AUDIO_I2S_MODE
+		       | SOLO_AUDIO_I2S_MULTI(3)
+		       | SOLO_AUDIO_MODE(OUTMODE_MASK));
+}
+
+void solo_g723_isr(struct solo_dev *solo_dev)
+{
+	struct snd_pcm_str *pstr =
+		&solo_dev->snd_pcm->streams[SNDRV_PCM_STREAM_CAPTURE];
+	struct snd_pcm_substream *ss;
+	struct solo_snd_pcm *solo_pcm;
+
+	for (ss = pstr->substream; ss != NULL; ss = ss->next) {
+		if (snd_pcm_substream_chip(ss) == NULL)
+			continue;
+
+		/* This means open() hasn't been called on this one */
+		if (snd_pcm_substream_chip(ss) == solo_dev)
+			continue;
+
+		/* Haven't triggered a start yet */
+		solo_pcm = snd_pcm_substream_chip(ss);
+		if (!solo_pcm->on)
+			continue;
+
+		snd_pcm_period_elapsed(ss);
+	}
+}
+
+static int snd_solo_hw_params(struct snd_pcm_substream *ss,
+			      struct snd_pcm_hw_params *hw_params)
+{
+	return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
+}
+
+static int snd_solo_hw_free(struct snd_pcm_substream *ss)
+{
+	return snd_pcm_lib_free_pages(ss);
+}
+
+static const struct snd_pcm_hardware snd_solo_pcm_hw = {
+	.info			= (SNDRV_PCM_INFO_MMAP |
+				   SNDRV_PCM_INFO_INTERLEAVED |
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				   SNDRV_PCM_INFO_MMAP_VALID),
+	.formats		= SNDRV_PCM_FMTBIT_U8,
+	.rates			= SNDRV_PCM_RATE_8000,
+	.rate_min		= SAMPLERATE,
+	.rate_max		= SAMPLERATE,
+	.channels_min		= 1,
+	.channels_max		= 1,
+	.buffer_bytes_max	= G723_MAX_BUFFER,
+	.period_bytes_min	= G723_PERIOD_BYTES,
+	.period_bytes_max	= G723_PERIOD_BYTES,
+	.periods_min		= PERIODS_MIN,
+	.periods_max		= PERIODS_MAX,
+};
+
+static int snd_solo_pcm_open(struct snd_pcm_substream *ss)
+{
+	struct solo_dev *solo_dev = snd_pcm_substream_chip(ss);
+	struct solo_snd_pcm *solo_pcm;
+
+	solo_pcm = kzalloc(sizeof(*solo_pcm), GFP_KERNEL);
+	if (solo_pcm == NULL)
+		goto oom;
+
+	solo_pcm->g723_buf = pci_alloc_consistent(solo_dev->pdev,
+						  G723_PERIOD_BYTES,
+						  &solo_pcm->g723_dma);
+	if (solo_pcm->g723_buf == NULL)
+		goto oom;
+
+	spin_lock_init(&solo_pcm->lock);
+	solo_pcm->solo_dev = solo_dev;
+	ss->runtime->hw = snd_solo_pcm_hw;
+
+	snd_pcm_substream_chip(ss) = solo_pcm;
+
+	return 0;
+
+oom:
+	kfree(solo_pcm);
+	return -ENOMEM;
+}
+
+static int snd_solo_pcm_close(struct snd_pcm_substream *ss)
+{
+	struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
+
+	snd_pcm_substream_chip(ss) = solo_pcm->solo_dev;
+	pci_free_consistent(solo_pcm->solo_dev->pdev, G723_PERIOD_BYTES,
+			    solo_pcm->g723_buf, solo_pcm->g723_dma);
+	kfree(solo_pcm);
+
+	return 0;
+}
+
+static int snd_solo_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
+{
+	struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
+	struct solo_dev *solo_dev = solo_pcm->solo_dev;
+	int ret = 0;
+
+	spin_lock(&solo_pcm->lock);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		if (solo_pcm->on == 0) {
+			/* If this is the first user, switch on interrupts */
+			if (atomic_inc_return(&solo_dev->snd_users) == 1)
+				solo_irq_on(solo_dev, SOLO_IRQ_G723);
+			solo_pcm->on = 1;
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		if (solo_pcm->on) {
+			/* If this was our last user, switch them off */
+			if (atomic_dec_return(&solo_dev->snd_users) == 0)
+				solo_irq_off(solo_dev, SOLO_IRQ_G723);
+			solo_pcm->on = 0;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	spin_unlock(&solo_pcm->lock);
+
+	return ret;
+}
+
+static int snd_solo_pcm_prepare(struct snd_pcm_substream *ss)
+{
+	return 0;
+}
+
+static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss)
+{
+	struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
+	struct solo_dev *solo_dev = solo_pcm->solo_dev;
+	snd_pcm_uframes_t idx = solo_reg_read(solo_dev, SOLO_AUDIO_STA) & 0x1f;
+
+	return idx * G723_FRAMES_PER_PAGE;
+}
+
+static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel,
+			     snd_pcm_uframes_t pos, void __user *dst,
+			     snd_pcm_uframes_t count)
+{
+	struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
+	struct solo_dev *solo_dev = solo_pcm->solo_dev;
+	int err, i;
+
+	for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) {
+		int page = (pos / G723_FRAMES_PER_PAGE) + i;
+
+		err = solo_p2m_dma_t(solo_dev, 0, solo_pcm->g723_dma,
+				     SOLO_G723_EXT_ADDR(solo_dev) +
+				     (page * G723_PERIOD_BLOCK) +
+				     (ss->number * G723_PERIOD_BYTES),
+				     G723_PERIOD_BYTES, 0, 0);
+		if (err)
+			return err;
+
+		err = copy_to_user(dst + (i * G723_PERIOD_BYTES),
+				   solo_pcm->g723_buf, G723_PERIOD_BYTES);
+
+		if (err)
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+static struct snd_pcm_ops snd_solo_pcm_ops = {
+	.open = snd_solo_pcm_open,
+	.close = snd_solo_pcm_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_solo_hw_params,
+	.hw_free = snd_solo_hw_free,
+	.prepare = snd_solo_pcm_prepare,
+	.trigger = snd_solo_pcm_trigger,
+	.pointer = snd_solo_pcm_pointer,
+	.copy = snd_solo_pcm_copy,
+};
+
+static int snd_solo_capture_volume_info(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *info)
+{
+	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	info->count = 1;
+	info->value.integer.min = 0;
+	info->value.integer.max = 15;
+	info->value.integer.step = 1;
+
+	return 0;
+}
+
+static int snd_solo_capture_volume_get(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *value)
+{
+	struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol);
+	u8 ch = value->id.numid - 1;
+
+	value->value.integer.value[0] = tw28_get_audio_gain(solo_dev, ch);
+
+	return 0;
+}
+
+static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *value)
+{
+	struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol);
+	u8 ch = value->id.numid - 1;
+	u8 old_val;
+
+	old_val = tw28_get_audio_gain(solo_dev, ch);
+	if (old_val == value->value.integer.value[0])
+		return 0;
+
+	tw28_set_audio_gain(solo_dev, ch, value->value.integer.value[0]);
+
+	return 1;
+}
+
+static struct snd_kcontrol_new snd_solo_capture_volume = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Capture Volume",
+	.info = snd_solo_capture_volume_info,
+	.get = snd_solo_capture_volume_get,
+	.put = snd_solo_capture_volume_put,
+};
+
+static int solo_snd_pcm_init(struct solo_dev *solo_dev)
+{
+	struct snd_card *card = solo_dev->snd_card;
+	struct snd_pcm *pcm;
+	struct snd_pcm_substream *ss;
+	int ret;
+	int i;
+
+	ret = snd_pcm_new(card, card->driver, 0, 0, solo_dev->nr_chans,
+			  &pcm);
+	if (ret < 0)
+		return ret;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+			&snd_solo_pcm_ops);
+
+	snd_pcm_chip(pcm) = solo_dev;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, card->shortname);
+
+	for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+	     ss; ss = ss->next, i++)
+		sprintf(ss->name, "Camera #%d Audio", i);
+
+	ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
+					SNDRV_DMA_TYPE_CONTINUOUS,
+					snd_dma_continuous_data(GFP_KERNEL),
+					G723_MAX_BUFFER, G723_MAX_BUFFER);
+	if (ret < 0)
+		return ret;
+
+	solo_dev->snd_pcm = pcm;
+
+	return 0;
+}
+
+int solo_g723_init(struct solo_dev *solo_dev)
+{
+	static struct snd_device_ops ops = { NULL };
+	struct snd_card *card;
+	struct snd_kcontrol_new kctl;
+	char name[32];
+	int ret;
+
+	atomic_set(&solo_dev->snd_users, 0);
+
+	/* Allows for easier mapping between video and audio */
+	sprintf(name, "Softlogic%d", solo_dev->vfd->num);
+
+	ret = snd_card_new(&solo_dev->pdev->dev,
+			   SNDRV_DEFAULT_IDX1, name, THIS_MODULE, 0,
+			   &solo_dev->snd_card);
+	if (ret < 0)
+		return ret;
+
+	card = solo_dev->snd_card;
+
+	strcpy(card->driver, SOLO6X10_NAME);
+	strcpy(card->shortname, "SOLO-6x10 Audio");
+	sprintf(card->longname, "%s on %s IRQ %d", card->shortname,
+		pci_name(solo_dev->pdev), solo_dev->pdev->irq);
+
+	ret = snd_device_new(card, SNDRV_DEV_LOWLEVEL, solo_dev, &ops);
+	if (ret < 0)
+		goto snd_error;
+
+	/* Mixer controls */
+	strcpy(card->mixername, "SOLO-6x10");
+	kctl = snd_solo_capture_volume;
+	kctl.count = solo_dev->nr_chans;
+
+	ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev));
+	if (ret < 0)
+		return ret;
+
+	ret = solo_snd_pcm_init(solo_dev);
+	if (ret < 0)
+		goto snd_error;
+
+	ret = snd_card_register(card);
+	if (ret < 0)
+		goto snd_error;
+
+	solo_g723_config(solo_dev);
+
+	dev_info(&solo_dev->pdev->dev, "Alsa sound card as %s\n", name);
+
+	return 0;
+
+snd_error:
+	snd_card_free(card);
+	return ret;
+}
+
+void solo_g723_exit(struct solo_dev *solo_dev)
+{
+	if (!solo_dev->snd_card)
+		return;
+
+	solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, 0);
+	solo_irq_off(solo_dev, SOLO_IRQ_G723);
+
+	snd_card_free(solo_dev->snd_card);
+	solo_dev->snd_card = NULL;
+}
diff --git a/drivers/media/pci/solo6x10/solo6x10-gpio.c b/drivers/media/pci/solo6x10/solo6x10-gpio.c
new file mode 100644
index 0000000000000..6d3b4a36bc119
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10-gpio.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+
+#include "solo6x10.h"
+
+static void solo_gpio_mode(struct solo_dev *solo_dev,
+			   unsigned int port_mask, unsigned int mode)
+{
+	int port;
+	unsigned int ret;
+
+	ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0);
+
+	/* To set gpio */
+	for (port = 0; port < 16; port++) {
+		if (!((1 << port) & port_mask))
+			continue;
+
+		ret &= (~(3 << (port << 1)));
+		ret |= ((mode & 3) << (port << 1));
+	}
+
+	solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_0, ret);
+
+	/* To set extended gpio - sensor */
+	ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1);
+
+	for (port = 0; port < 16; port++) {
+		if (!((1 << (port + 16)) & port_mask))
+			continue;
+
+		if (!mode)
+			ret &= ~(1 << port);
+		else
+			ret |= 1 << port;
+	}
+
+	solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret);
+}
+
+static void solo_gpio_set(struct solo_dev *solo_dev, unsigned int value)
+{
+	solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
+		       solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) | value);
+}
+
+static void solo_gpio_clear(struct solo_dev *solo_dev, unsigned int value)
+{
+	solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
+		       solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) & ~value);
+}
+
+static void solo_gpio_config(struct solo_dev *solo_dev)
+{
+	/* Video reset */
+	solo_gpio_mode(solo_dev, 0x30, 1);
+	solo_gpio_clear(solo_dev, 0x30);
+	udelay(100);
+	solo_gpio_set(solo_dev, 0x30);
+	udelay(100);
+
+	/* Warning: Don't touch the next line unless you're sure of what
+	 * you're doing: first four gpio [0-3] are used for video. */
+	solo_gpio_mode(solo_dev, 0x0f, 2);
+
+	/* We use bit 8-15 of SOLO_GPIO_CONFIG_0 for relay purposes */
+	solo_gpio_mode(solo_dev, 0xff00, 1);
+
+	/* Initially set relay status to 0 */
+	solo_gpio_clear(solo_dev, 0xff00);
+}
+
+int solo_gpio_init(struct solo_dev *solo_dev)
+{
+	solo_gpio_config(solo_dev);
+	return 0;
+}
+
+void solo_gpio_exit(struct solo_dev *solo_dev)
+{
+	solo_gpio_clear(solo_dev, 0x30);
+	solo_gpio_config(solo_dev);
+}
diff --git a/drivers/media/pci/solo6x10/solo6x10-i2c.c b/drivers/media/pci/solo6x10/solo6x10-i2c.c
new file mode 100644
index 0000000000000..c908672b2c401
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10-i2c.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+/* XXX: The SOLO6x10 i2c does not have separate interrupts for each i2c
+ * channel. The bus can only handle one i2c event at a time. The below handles
+ * this all wrong. We should be using the status registers to see if the bus
+ * is in use, and have a global lock to check the status register. Also,
+ * the bulk of the work should be handled out-of-interrupt. The ugly loops
+ * that occur during interrupt scare me. The ISR should merely signal
+ * thread context, ACK the interrupt, and move on. -- BenC */
+
+#include <linux/kernel.h>
+
+#include "solo6x10.h"
+
+u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off)
+{
+	struct i2c_msg msgs[2];
+	u8 data;
+
+	msgs[0].flags = 0;
+	msgs[0].addr = addr;
+	msgs[0].len = 1;
+	msgs[0].buf = &off;
+
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].addr = addr;
+	msgs[1].len = 1;
+	msgs[1].buf = &data;
+
+	i2c_transfer(&solo_dev->i2c_adap[id], msgs, 2);
+
+	return data;
+}
+
+void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr,
+			u8 off, u8 data)
+{
+	struct i2c_msg msgs;
+	u8 buf[2];
+
+	buf[0] = off;
+	buf[1] = data;
+	msgs.flags = 0;
+	msgs.addr = addr;
+	msgs.len = 2;
+	msgs.buf = buf;
+
+	i2c_transfer(&solo_dev->i2c_adap[id], &msgs, 1);
+}
+
+static void solo_i2c_flush(struct solo_dev *solo_dev, int wr)
+{
+	u32 ctrl;
+
+	ctrl = SOLO_IIC_CH_SET(solo_dev->i2c_id);
+
+	if (solo_dev->i2c_state == IIC_STATE_START)
+		ctrl |= SOLO_IIC_START;
+
+	if (wr) {
+		ctrl |= SOLO_IIC_WRITE;
+	} else {
+		ctrl |= SOLO_IIC_READ;
+		if (!(solo_dev->i2c_msg->flags & I2C_M_NO_RD_ACK))
+			ctrl |= SOLO_IIC_ACK_EN;
+	}
+
+	if (solo_dev->i2c_msg_ptr == solo_dev->i2c_msg->len)
+		ctrl |= SOLO_IIC_STOP;
+
+	solo_reg_write(solo_dev, SOLO_IIC_CTRL, ctrl);
+}
+
+static void solo_i2c_start(struct solo_dev *solo_dev)
+{
+	u32 addr = solo_dev->i2c_msg->addr << 1;
+
+	if (solo_dev->i2c_msg->flags & I2C_M_RD)
+		addr |= 1;
+
+	solo_dev->i2c_state = IIC_STATE_START;
+	solo_reg_write(solo_dev, SOLO_IIC_TXD, addr);
+	solo_i2c_flush(solo_dev, 1);
+}
+
+static void solo_i2c_stop(struct solo_dev *solo_dev)
+{
+	solo_irq_off(solo_dev, SOLO_IRQ_IIC);
+	solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
+	solo_dev->i2c_state = IIC_STATE_STOP;
+	wake_up(&solo_dev->i2c_wait);
+}
+
+static int solo_i2c_handle_read(struct solo_dev *solo_dev)
+{
+prepare_read:
+	if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
+		solo_i2c_flush(solo_dev, 0);
+		return 0;
+	}
+
+	solo_dev->i2c_msg_ptr = 0;
+	solo_dev->i2c_msg++;
+	solo_dev->i2c_msg_num--;
+
+	if (solo_dev->i2c_msg_num == 0) {
+		solo_i2c_stop(solo_dev);
+		return 0;
+	}
+
+	if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
+		solo_i2c_start(solo_dev);
+	} else {
+		if (solo_dev->i2c_msg->flags & I2C_M_RD)
+			goto prepare_read;
+		else
+			solo_i2c_stop(solo_dev);
+	}
+
+	return 0;
+}
+
+static int solo_i2c_handle_write(struct solo_dev *solo_dev)
+{
+retry_write:
+	if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
+		solo_reg_write(solo_dev, SOLO_IIC_TXD,
+			       solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr]);
+		solo_dev->i2c_msg_ptr++;
+		solo_i2c_flush(solo_dev, 1);
+		return 0;
+	}
+
+	solo_dev->i2c_msg_ptr = 0;
+	solo_dev->i2c_msg++;
+	solo_dev->i2c_msg_num--;
+
+	if (solo_dev->i2c_msg_num == 0) {
+		solo_i2c_stop(solo_dev);
+		return 0;
+	}
+
+	if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
+		solo_i2c_start(solo_dev);
+	} else {
+		if (solo_dev->i2c_msg->flags & I2C_M_RD)
+			solo_i2c_stop(solo_dev);
+		else
+			goto retry_write;
+	}
+
+	return 0;
+}
+
+int solo_i2c_isr(struct solo_dev *solo_dev)
+{
+	u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL);
+	int ret = -EINVAL;
+
+
+	if (CHK_FLAGS(status, SOLO_IIC_STATE_TRNS | SOLO_IIC_STATE_SIG_ERR)
+	    || solo_dev->i2c_id < 0) {
+		solo_i2c_stop(solo_dev);
+		return -ENXIO;
+	}
+
+	switch (solo_dev->i2c_state) {
+	case IIC_STATE_START:
+		if (solo_dev->i2c_msg->flags & I2C_M_RD) {
+			solo_dev->i2c_state = IIC_STATE_READ;
+			ret = solo_i2c_handle_read(solo_dev);
+			break;
+		}
+
+		solo_dev->i2c_state = IIC_STATE_WRITE;
+	case IIC_STATE_WRITE:
+		ret = solo_i2c_handle_write(solo_dev);
+		break;
+
+	case IIC_STATE_READ:
+		solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr] =
+			solo_reg_read(solo_dev, SOLO_IIC_RXD);
+		solo_dev->i2c_msg_ptr++;
+
+		ret = solo_i2c_handle_read(solo_dev);
+		break;
+
+	default:
+		solo_i2c_stop(solo_dev);
+	}
+
+	return ret;
+}
+
+static int solo_i2c_master_xfer(struct i2c_adapter *adap,
+				struct i2c_msg msgs[], int num)
+{
+	struct solo_dev *solo_dev = adap->algo_data;
+	unsigned long timeout;
+	int ret;
+	int i;
+	DEFINE_WAIT(wait);
+
+	for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
+		if (&solo_dev->i2c_adap[i] == adap)
+			break;
+	}
+
+	if (i == SOLO_I2C_ADAPTERS)
+		return num; /* XXX Right return value for failure? */
+
+	mutex_lock(&solo_dev->i2c_mutex);
+	solo_dev->i2c_id = i;
+	solo_dev->i2c_msg = msgs;
+	solo_dev->i2c_msg_num = num;
+	solo_dev->i2c_msg_ptr = 0;
+
+	solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
+	solo_irq_on(solo_dev, SOLO_IRQ_IIC);
+	solo_i2c_start(solo_dev);
+
+	timeout = HZ / 2;
+
+	for (;;) {
+		prepare_to_wait(&solo_dev->i2c_wait, &wait,
+				TASK_INTERRUPTIBLE);
+
+		if (solo_dev->i2c_state == IIC_STATE_STOP)
+			break;
+
+		timeout = schedule_timeout(timeout);
+		if (!timeout)
+			break;
+
+		if (signal_pending(current))
+			break;
+	}
+
+	finish_wait(&solo_dev->i2c_wait, &wait);
+	ret = num - solo_dev->i2c_msg_num;
+	solo_dev->i2c_state = IIC_STATE_IDLE;
+	solo_dev->i2c_id = -1;
+
+	mutex_unlock(&solo_dev->i2c_mutex);
+
+	return ret;
+}
+
+static u32 solo_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm solo_i2c_algo = {
+	.master_xfer	= solo_i2c_master_xfer,
+	.functionality	= solo_i2c_functionality,
+};
+
+int solo_i2c_init(struct solo_dev *solo_dev)
+{
+	int i;
+	int ret;
+
+	solo_reg_write(solo_dev, SOLO_IIC_CFG,
+		       SOLO_IIC_PRESCALE(8) | SOLO_IIC_ENABLE);
+
+	solo_dev->i2c_id = -1;
+	solo_dev->i2c_state = IIC_STATE_IDLE;
+	init_waitqueue_head(&solo_dev->i2c_wait);
+	mutex_init(&solo_dev->i2c_mutex);
+
+	for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
+		struct i2c_adapter *adap = &solo_dev->i2c_adap[i];
+
+		snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d",
+			 SOLO6X10_NAME, i);
+		adap->algo = &solo_i2c_algo;
+		adap->algo_data = solo_dev;
+		adap->retries = 1;
+		adap->dev.parent = &solo_dev->pdev->dev;
+
+		ret = i2c_add_adapter(adap);
+		if (ret) {
+			adap->algo_data = NULL;
+			break;
+		}
+	}
+
+	if (ret) {
+		for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
+			if (!solo_dev->i2c_adap[i].algo_data)
+				break;
+			i2c_del_adapter(&solo_dev->i2c_adap[i]);
+			solo_dev->i2c_adap[i].algo_data = NULL;
+		}
+		return ret;
+	}
+
+	return 0;
+}
+
+void solo_i2c_exit(struct solo_dev *solo_dev)
+{
+	int i;
+
+	for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
+		if (!solo_dev->i2c_adap[i].algo_data)
+			continue;
+		i2c_del_adapter(&solo_dev->i2c_adap[i]);
+		solo_dev->i2c_adap[i].algo_data = NULL;
+	}
+}
diff --git a/drivers/media/pci/solo6x10/solo6x10-jpeg.h b/drivers/media/pci/solo6x10/solo6x10-jpeg.h
new file mode 100644
index 0000000000000..1c66a46da514f
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10-jpeg.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+#ifndef __SOLO6X10_JPEG_H
+#define __SOLO6X10_JPEG_H
+
+static const unsigned char jpeg_header[] = {
+	0xff, 0xd8, 0xff, 0xfe, 0x00, 0x0d, 0x42, 0x6c,
+	0x75, 0x65, 0x63, 0x68, 0x65, 0x72, 0x72, 0x79,
+	0x20, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x20, 0x16,
+	0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, 0x1a, 0x1c,
+	0x24, 0x22, 0x20, 0x26, 0x30, 0x50, 0x34, 0x30,
+	0x2c, 0x2c, 0x30, 0x62, 0x46, 0x4a, 0x3a, 0x50,
+	0x74, 0x66, 0x7a, 0x78, 0x72, 0x66, 0x70, 0x6e,
+	0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, 0xae, 0x8a,
+	0x6e, 0x70, 0xa0, 0xda, 0xa2, 0xae, 0xbe, 0xc4,
+	0xce, 0xd0, 0xce, 0x7c, 0x9a, 0xe2, 0xf2, 0xe0,
+	0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, 0xff, 0xdb,
+	0x00, 0x43, 0x01, 0x22, 0x24, 0x24, 0x30, 0x2a,
+	0x30, 0x5e, 0x34, 0x34, 0x5e, 0xc6, 0x84, 0x70,
+	0x84, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+	0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+	0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+	0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+	0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+	0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+	0xc6, 0xc6, 0xc6, 0xff, 0xc4, 0x01, 0xa2, 0x00,
+	0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01,
+	0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
+	0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03,
+	0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41,
+	0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14,
+	0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1,
+	0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62,
+	0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19,
+	0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34,
+	0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
+	0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
+	0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
+	0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74,
+	0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84,
+	0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
+	0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2,
+	0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
+	0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+	0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
+	0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+	0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5,
+	0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
+	0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01,
+	0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	0x08, 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01,
+	0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
+	0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02,
+	0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12,
+	0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32,
+	0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1,
+	0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72,
+	0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1,
+	0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29,
+	0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43,
+	0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53,
+	0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63,
+	0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73,
+	0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82,
+	0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
+	0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+	0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
+	0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+	0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
+	0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5,
+	0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4,
+	0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3,
+	0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff,
+	0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x02, 0xc0,
+	0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03,
+	0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01,
+	0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
+};
+
+/* This is the byte marker for the start of SOF0: 0xffc0 marker */
+#define SOF0_START	575
+
+/* This is the byte marker for the start of the DQT */
+#define DQT_START	17
+#define DQT_LEN		138
+static const unsigned char jpeg_dqt[4][DQT_LEN] = {
+	{
+		0xff, 0xdb, 0x00, 0x43, 0x00,
+		0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07,
+		0x07, 0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14,
+		0x0d, 0x0c, 0x0b, 0x0b, 0x0c, 0x19, 0x12, 0x13,
+		0x0f, 0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a,
+		0x1c, 0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22,
+		0x2c, 0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c,
+		0x30, 0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, 0x39,
+		0x3d, 0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32,
+		0xff, 0xdb, 0x00, 0x43, 0x01,
+		0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0d,
+		0x0d, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, 0x32,
+		0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
+		0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
+		0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
+		0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
+		0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
+		0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32
+	}, {
+		0xff, 0xdb, 0x00, 0x43, 0x00,
+		0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e,
+		0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
+		0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
+		0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33,
+		0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44,
+		0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57,
+		0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
+		0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
+		0xff, 0xdb, 0x00, 0x43, 0x01,
+		0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
+		0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
+	}, {
+		0xff, 0xdb, 0x00, 0x43, 0x00,
+		0x20, 0x16, 0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c,
+		0x1a, 0x1c, 0x24, 0x22, 0x20, 0x26, 0x30, 0x50,
+		0x34, 0x30, 0x2c, 0x2c, 0x30, 0x62, 0x46, 0x4a,
+		0x3a, 0x50, 0x74, 0x66, 0x7a, 0x78, 0x72, 0x66,
+		0x70, 0x6e, 0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88,
+		0xae, 0x8a, 0x6e, 0x70, 0xa0, 0xda, 0xa2, 0xae,
+		0xbe, 0xc4, 0xce, 0xd0, 0xce, 0x7c, 0x9a, 0xe2,
+		0xf2, 0xe0, 0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6,
+		0xff, 0xdb, 0x00, 0x43, 0x01,
+		0x22, 0x24, 0x24, 0x30, 0x2a, 0x30, 0x5e, 0x34,
+		0x34, 0x5e, 0xc6, 0x84, 0x70, 0x84, 0xc6, 0xc6,
+		0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+		0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+		0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+		0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+		0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+		0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6
+	}, {
+		0xff, 0xdb, 0x00, 0x43, 0x00,
+		0x30, 0x21, 0x24, 0x2a, 0x24, 0x1e, 0x30, 0x2a,
+		0x27, 0x2a, 0x36, 0x33, 0x30, 0x39, 0x48, 0x78,
+		0x4e, 0x48, 0x42, 0x42, 0x48, 0x93, 0x69, 0x6f,
+		0x57, 0x78, 0xae, 0x99, 0xb7, 0xb4, 0xab, 0x99,
+		0xa8, 0xa5, 0xc0, 0xd8, 0xff, 0xea, 0xc0, 0xcc,
+		0xff, 0xcf, 0xa5, 0xa8, 0xf0, 0xff, 0xf3, 0xff,
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xba, 0xe7, 0xff,
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+		0xff, 0xdb, 0x00, 0x43, 0x01,
+		0x33, 0x36, 0x36, 0x48, 0x3f, 0x48, 0x8d, 0x4e,
+		0x4e, 0x8d, 0xff, 0xc6, 0xa8, 0xc6, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+	}
+};
+
+#endif /* __SOLO6X10_JPEG_H */
diff --git a/drivers/media/pci/solo6x10/solo6x10-offsets.h b/drivers/media/pci/solo6x10/solo6x10-offsets.h
new file mode 100644
index 0000000000000..d6aea7c2a6769
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10-offsets.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+#ifndef __SOLO6X10_OFFSETS_H
+#define __SOLO6X10_OFFSETS_H
+
+#define SOLO_DISP_EXT_ADDR			0x00000000
+#define SOLO_DISP_EXT_SIZE			0x00480000
+
+#define SOLO_EOSD_EXT_ADDR \
+	(SOLO_DISP_EXT_ADDR + SOLO_DISP_EXT_SIZE)
+#define SOLO_EOSD_EXT_SIZE(__solo) \
+	(__solo->type == SOLO_DEV_6010 ? 0x10000 : 0x20000)
+#define SOLO_EOSD_EXT_SIZE_MAX			0x20000
+#define SOLO_EOSD_EXT_AREA(__solo) \
+	(SOLO_EOSD_EXT_SIZE(__solo) * 32)
+#define SOLO_EOSD_EXT_ADDR_CHAN(__solo, ch) \
+	(SOLO_EOSD_EXT_ADDR + SOLO_EOSD_EXT_SIZE(__solo) * (ch))
+
+#define SOLO_MOTION_EXT_ADDR(__solo) \
+	(SOLO_EOSD_EXT_ADDR + SOLO_EOSD_EXT_AREA(__solo))
+#define SOLO_MOTION_EXT_SIZE			0x00080000
+
+#define SOLO_G723_EXT_ADDR(__solo) \
+	(SOLO_MOTION_EXT_ADDR(__solo) + SOLO_MOTION_EXT_SIZE)
+#define SOLO_G723_EXT_SIZE			0x00010000
+
+#define SOLO_CAP_EXT_ADDR(__solo) \
+	(SOLO_G723_EXT_ADDR(__solo) + SOLO_G723_EXT_SIZE)
+
+/* 18 is the maximum number of pages required for PAL@D1, the largest frame
+ * possible */
+#define SOLO_CAP_PAGE_SIZE			(18 << 16)
+
+/* Always allow the encoder enough for 16 channels, even if we have less. The
+ * exception is if we have card with only 32Megs of memory. */
+#define SOLO_CAP_EXT_SIZE(__solo) \
+	((((__solo->sdram_size <= (32 << 20)) ? 4 : 16) + 1)	\
+	 * SOLO_CAP_PAGE_SIZE)
+
+#define SOLO_EREF_EXT_ADDR(__solo) \
+	(SOLO_CAP_EXT_ADDR(__solo) + SOLO_CAP_EXT_SIZE(__solo))
+#define SOLO_EREF_EXT_SIZE			0x00140000
+#define SOLO_EREF_EXT_AREA(__solo) \
+	(SOLO_EREF_EXT_SIZE * __solo->nr_chans * 2)
+
+#define __SOLO_JPEG_MIN_SIZE(__solo)		(__solo->nr_chans * 0x00080000)
+
+#define SOLO_MP4E_EXT_ADDR(__solo) \
+	(SOLO_EREF_EXT_ADDR(__solo) + SOLO_EREF_EXT_AREA(__solo))
+#define SOLO_MP4E_EXT_SIZE(__solo) \
+	max((__solo->nr_chans * 0x00080000),				\
+	    min(((__solo->sdram_size - SOLO_MP4E_EXT_ADDR(__solo)) -	\
+		 __SOLO_JPEG_MIN_SIZE(__solo)), 0x00ff0000))
+
+#define __SOLO_JPEG_MIN_SIZE(__solo)		(__solo->nr_chans * 0x00080000)
+#define SOLO_JPEG_EXT_ADDR(__solo) \
+		(SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo))
+#define SOLO_JPEG_EXT_SIZE(__solo) \
+	max(__SOLO_JPEG_MIN_SIZE(__solo),				\
+	    min((__solo->sdram_size - SOLO_JPEG_EXT_ADDR(__solo)), 0x00ff0000))
+
+#define SOLO_SDRAM_END(__solo) \
+	(SOLO_JPEG_EXT_ADDR(__solo) + SOLO_JPEG_EXT_SIZE(__solo))
+
+#endif /* __SOLO6X10_OFFSETS_H */
diff --git a/drivers/media/pci/solo6x10/solo6x10-p2m.c b/drivers/media/pci/solo6x10/solo6x10-p2m.c
new file mode 100644
index 0000000000000..8c8484674d2f6
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10-p2m.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "solo6x10.h"
+
+static int multi_p2m;
+module_param(multi_p2m, uint, 0644);
+MODULE_PARM_DESC(multi_p2m,
+		 "Use multiple P2M DMA channels (default: no, 6010-only)");
+
+static int desc_mode;
+module_param(desc_mode, uint, 0644);
+MODULE_PARM_DESC(desc_mode,
+		 "Allow use of descriptor mode DMA (default: no, 6010-only)");
+
+int solo_p2m_dma(struct solo_dev *solo_dev, int wr,
+		 void *sys_addr, u32 ext_addr, u32 size,
+		 int repeat, u32 ext_size)
+{
+	dma_addr_t dma_addr;
+	int ret;
+
+	if (WARN_ON_ONCE((unsigned long)sys_addr & 0x03))
+		return -EINVAL;
+	if (WARN_ON_ONCE(!size))
+		return -EINVAL;
+
+	dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size,
+				  wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+	if (pci_dma_mapping_error(solo_dev->pdev, dma_addr))
+		return -ENOMEM;
+
+	ret = solo_p2m_dma_t(solo_dev, wr, dma_addr, ext_addr, size,
+			     repeat, ext_size);
+
+	pci_unmap_single(solo_dev->pdev, dma_addr, size,
+			 wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+
+	return ret;
+}
+
+/* Mutex must be held for p2m_id before calling this!! */
+int solo_p2m_dma_desc(struct solo_dev *solo_dev,
+		      struct solo_p2m_desc *desc, dma_addr_t desc_dma,
+		      int desc_cnt)
+{
+	struct solo_p2m_dev *p2m_dev;
+	unsigned int timeout;
+	unsigned int config = 0;
+	int ret = 0;
+	int p2m_id = 0;
+
+	/* Get next ID. According to Softlogic, 6110 has problems on !=0 P2M */
+	if (solo_dev->type != SOLO_DEV_6110 && multi_p2m) {
+		p2m_id = atomic_inc_return(&solo_dev->p2m_count) % SOLO_NR_P2M;
+		if (p2m_id < 0)
+			p2m_id = -p2m_id;
+	}
+
+	p2m_dev = &solo_dev->p2m_dev[p2m_id];
+
+	if (mutex_lock_interruptible(&p2m_dev->mutex))
+		return -EINTR;
+
+	reinit_completion(&p2m_dev->completion);
+	p2m_dev->error = 0;
+
+	if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && desc_mode) {
+		/* For 6010 with more than one desc, we can do a one-shot */
+		p2m_dev->desc_count = p2m_dev->desc_idx = 0;
+		config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(p2m_id));
+
+		solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(p2m_id), desc_dma);
+		solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(p2m_id), desc_cnt);
+		solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config |
+			       SOLO_P2M_DESC_MODE);
+	} else {
+		/* For single descriptors and 6110, we need to run each desc */
+		p2m_dev->desc_count = desc_cnt;
+		p2m_dev->desc_idx = 1;
+		p2m_dev->descs = desc;
+
+		solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(p2m_id),
+			       desc[1].dma_addr);
+		solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(p2m_id),
+			       desc[1].ext_addr);
+		solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(p2m_id),
+			       desc[1].cfg);
+		solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id),
+			       desc[1].ctrl);
+	}
+
+	timeout = wait_for_completion_timeout(&p2m_dev->completion,
+					      solo_dev->p2m_jiffies);
+
+	if (WARN_ON_ONCE(p2m_dev->error))
+		ret = -EIO;
+	else if (timeout == 0) {
+		solo_dev->p2m_timeouts++;
+		ret = -EAGAIN;
+	}
+
+	solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), 0);
+
+	/* Don't write here for the no_desc_mode case, because config is 0.
+	 * We can't test no_desc_mode again, it might race. */
+	if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && config)
+		solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config);
+
+	mutex_unlock(&p2m_dev->mutex);
+
+	return ret;
+}
+
+void solo_p2m_fill_desc(struct solo_p2m_desc *desc, int wr,
+			dma_addr_t dma_addr, u32 ext_addr, u32 size,
+			int repeat, u32 ext_size)
+{
+	WARN_ON_ONCE(dma_addr & 0x03);
+	WARN_ON_ONCE(!size);
+
+	desc->cfg = SOLO_P2M_COPY_SIZE(size >> 2);
+	desc->ctrl = SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) |
+		(wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON;
+
+	if (repeat) {
+		desc->cfg |= SOLO_P2M_EXT_INC(ext_size >> 2);
+		desc->ctrl |=  SOLO_P2M_PCI_INC(size >> 2) |
+			 SOLO_P2M_REPEAT(repeat);
+	}
+
+	desc->dma_addr = dma_addr;
+	desc->ext_addr = ext_addr;
+}
+
+int solo_p2m_dma_t(struct solo_dev *solo_dev, int wr,
+		   dma_addr_t dma_addr, u32 ext_addr, u32 size,
+		   int repeat, u32 ext_size)
+{
+	struct solo_p2m_desc desc[2];
+
+	solo_p2m_fill_desc(&desc[1], wr, dma_addr, ext_addr, size, repeat,
+			   ext_size);
+
+	/* No need for desc_dma since we know it is a single-shot */
+	return solo_p2m_dma_desc(solo_dev, desc, 0, 1);
+}
+
+void solo_p2m_isr(struct solo_dev *solo_dev, int id)
+{
+	struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id];
+	struct solo_p2m_desc *desc;
+
+	if (p2m_dev->desc_count <= p2m_dev->desc_idx) {
+		complete(&p2m_dev->completion);
+		return;
+	}
+
+	/* Setup next descriptor */
+	p2m_dev->desc_idx++;
+	desc = &p2m_dev->descs[p2m_dev->desc_idx];
+
+	solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
+	solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), desc->dma_addr);
+	solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), desc->ext_addr);
+	solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id), desc->cfg);
+	solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), desc->ctrl);
+}
+
+void solo_p2m_error_isr(struct solo_dev *solo_dev)
+{
+	unsigned int err = solo_reg_read(solo_dev, SOLO_PCI_ERR);
+	struct solo_p2m_dev *p2m_dev;
+	int i;
+
+	if (!(err & (SOLO_PCI_ERR_P2M | SOLO_PCI_ERR_P2M_DESC)))
+		return;
+
+	for (i = 0; i < SOLO_NR_P2M; i++) {
+		p2m_dev = &solo_dev->p2m_dev[i];
+		p2m_dev->error = 1;
+		solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
+		complete(&p2m_dev->completion);
+	}
+}
+
+void solo_p2m_exit(struct solo_dev *solo_dev)
+{
+	int i;
+
+	for (i = 0; i < SOLO_NR_P2M; i++)
+		solo_irq_off(solo_dev, SOLO_IRQ_P2M(i));
+}
+
+static int solo_p2m_test(struct solo_dev *solo_dev, int base, int size)
+{
+	u32 *wr_buf;
+	u32 *rd_buf;
+	int i;
+	int ret = -EIO;
+	int order = get_order(size);
+
+	wr_buf = (u32 *)__get_free_pages(GFP_KERNEL, order);
+	if (wr_buf == NULL)
+		return -1;
+
+	rd_buf = (u32 *)__get_free_pages(GFP_KERNEL, order);
+	if (rd_buf == NULL) {
+		free_pages((unsigned long)wr_buf, order);
+		return -1;
+	}
+
+	for (i = 0; i < (size >> 3); i++)
+		*(wr_buf + i) = (i << 16) | (i + 1);
+
+	for (i = (size >> 3); i < (size >> 2); i++)
+		*(wr_buf + i) = ~((i << 16) | (i + 1));
+
+	memset(rd_buf, 0x55, size);
+
+	if (solo_p2m_dma(solo_dev, 1, wr_buf, base, size, 0, 0))
+		goto test_fail;
+
+	if (solo_p2m_dma(solo_dev, 0, rd_buf, base, size, 0, 0))
+		goto test_fail;
+
+	for (i = 0; i < (size >> 2); i++) {
+		if (*(wr_buf + i) != *(rd_buf + i))
+			goto test_fail;
+	}
+
+	ret = 0;
+
+test_fail:
+	free_pages((unsigned long)wr_buf, order);
+	free_pages((unsigned long)rd_buf, order);
+
+	return ret;
+}
+
+int solo_p2m_init(struct solo_dev *solo_dev)
+{
+	struct solo_p2m_dev *p2m_dev;
+	int i;
+
+	for (i = 0; i < SOLO_NR_P2M; i++) {
+		p2m_dev = &solo_dev->p2m_dev[i];
+
+		mutex_init(&p2m_dev->mutex);
+		init_completion(&p2m_dev->completion);
+
+		solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
+		solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i),
+			       SOLO_P2M_CSC_16BIT_565 |
+			       SOLO_P2M_DESC_INTR_OPT |
+			       SOLO_P2M_DMA_INTERVAL(0) |
+			       SOLO_P2M_PCI_MASTER_MODE);
+		solo_irq_on(solo_dev, SOLO_IRQ_P2M(i));
+	}
+
+	/* Find correct SDRAM size */
+	for (solo_dev->sdram_size = 0, i = 2; i >= 0; i--) {
+		solo_reg_write(solo_dev, SOLO_DMA_CTRL,
+			       SOLO_DMA_CTRL_REFRESH_CYCLE(1) |
+			       SOLO_DMA_CTRL_SDRAM_SIZE(i) |
+			       SOLO_DMA_CTRL_SDRAM_CLK_INVERT |
+			       SOLO_DMA_CTRL_READ_CLK_SELECT |
+			       SOLO_DMA_CTRL_LATENCY(1));
+
+		solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config |
+			       SOLO_SYS_CFG_RESET);
+		solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config);
+
+		switch (i) {
+		case 2:
+			if (solo_p2m_test(solo_dev, 0x07ff0000, 0x00010000) ||
+			    solo_p2m_test(solo_dev, 0x05ff0000, 0x00010000))
+				continue;
+			break;
+
+		case 1:
+			if (solo_p2m_test(solo_dev, 0x03ff0000, 0x00010000))
+				continue;
+			break;
+
+		default:
+			if (solo_p2m_test(solo_dev, 0x01ff0000, 0x00010000))
+				continue;
+		}
+
+		solo_dev->sdram_size = (32 << 20) << i;
+		break;
+	}
+
+	if (!solo_dev->sdram_size) {
+		dev_err(&solo_dev->pdev->dev, "Error detecting SDRAM size\n");
+		return -EIO;
+	}
+
+	if (SOLO_SDRAM_END(solo_dev) > solo_dev->sdram_size) {
+		dev_err(&solo_dev->pdev->dev,
+			"SDRAM is not large enough (%u < %u)\n",
+			solo_dev->sdram_size, SOLO_SDRAM_END(solo_dev));
+		return -EIO;
+	}
+
+	return 0;
+}
diff --git a/drivers/media/pci/solo6x10/solo6x10-regs.h b/drivers/media/pci/solo6x10/solo6x10-regs.h
new file mode 100644
index 0000000000000..e34ac56ab101e
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10-regs.h
@@ -0,0 +1,635 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+#ifndef __SOLO6X10_REGISTERS_H
+#define __SOLO6X10_REGISTERS_H
+
+#include "solo6x10-offsets.h"
+
+/* Global 6010 system configuration */
+#define SOLO_SYS_CFG				0x0000
+#define   SOLO_SYS_CFG_FOUT_EN			0x00000001
+#define   SOLO_SYS_CFG_PLL_BYPASS		0x00000002
+#define   SOLO_SYS_CFG_PLL_PWDN			0x00000004
+#define   SOLO_SYS_CFG_OUTDIV(__n)		(((__n) & 0x003) << 3)
+#define   SOLO_SYS_CFG_FEEDBACKDIV(__n)		(((__n) & 0x1ff) << 5)
+#define   SOLO_SYS_CFG_INPUTDIV(__n)		(((__n) & 0x01f) << 14)
+#define   SOLO_SYS_CFG_CLOCK_DIV		0x00080000
+#define   SOLO_SYS_CFG_NCLK_DELAY(__n)		(((__n) & 0x003) << 24)
+#define   SOLO_SYS_CFG_PCLK_DELAY(__n)		(((__n) & 0x00f) << 26)
+#define   SOLO_SYS_CFG_SDRAM64BIT		0x40000000
+#define   SOLO_SYS_CFG_RESET			0x80000000
+
+#define	SOLO_DMA_CTRL				0x0004
+#define	  SOLO_DMA_CTRL_REFRESH_CYCLE(n)	((n)<<8)
+/* 0=16/32MB, 1=32/64MB, 2=64/128MB, 3=128/256MB */
+#define	  SOLO_DMA_CTRL_SDRAM_SIZE(n)		((n)<<6)
+#define	  SOLO_DMA_CTRL_SDRAM_CLK_INVERT	(1<<5)
+#define	  SOLO_DMA_CTRL_STROBE_SELECT		(1<<4)
+#define	  SOLO_DMA_CTRL_READ_DATA_SELECT	(1<<3)
+#define	  SOLO_DMA_CTRL_READ_CLK_SELECT		(1<<2)
+#define	  SOLO_DMA_CTRL_LATENCY(n)		((n)<<0)
+
+/* Some things we set in this are undocumented. Why Softlogic?!?! */
+#define SOLO_DMA_CTRL1				0x0008
+
+#define SOLO_SYS_VCLK				0x000C
+#define	  SOLO_VCLK_INVERT			(1<<22)
+/* 0=sys_clk/4, 1=sys_clk/2, 2=clk_in/2 of system input */
+#define	  SOLO_VCLK_SELECT(n)			((n)<<20)
+#define	  SOLO_VCLK_VIN1415_DELAY(n)		((n)<<14)
+#define	  SOLO_VCLK_VIN1213_DELAY(n)		((n)<<12)
+#define	  SOLO_VCLK_VIN1011_DELAY(n)		((n)<<10)
+#define	  SOLO_VCLK_VIN0809_DELAY(n)		((n)<<8)
+#define	  SOLO_VCLK_VIN0607_DELAY(n)		((n)<<6)
+#define	  SOLO_VCLK_VIN0405_DELAY(n)		((n)<<4)
+#define	  SOLO_VCLK_VIN0203_DELAY(n)		((n)<<2)
+#define	  SOLO_VCLK_VIN0001_DELAY(n)		((n)<<0)
+
+#define SOLO_IRQ_STAT				0x0010
+#define SOLO_IRQ_MASK				0x0014
+#define	  SOLO_IRQ_P2M(n)			(1<<((n)+17))
+#define	  SOLO_IRQ_GPIO				(1<<16)
+#define	  SOLO_IRQ_VIDEO_LOSS			(1<<15)
+#define	  SOLO_IRQ_VIDEO_IN			(1<<14)
+#define	  SOLO_IRQ_MOTION			(1<<13)
+#define	  SOLO_IRQ_ATA_CMD			(1<<12)
+#define	  SOLO_IRQ_ATA_DIR			(1<<11)
+#define	  SOLO_IRQ_PCI_ERR			(1<<10)
+#define	  SOLO_IRQ_PS2_1			(1<<9)
+#define	  SOLO_IRQ_PS2_0			(1<<8)
+#define	  SOLO_IRQ_SPI				(1<<7)
+#define	  SOLO_IRQ_IIC				(1<<6)
+#define	  SOLO_IRQ_UART(n)			(1<<((n) + 4))
+#define	  SOLO_IRQ_G723				(1<<3)
+#define	  SOLO_IRQ_DECODER			(1<<1)
+#define	  SOLO_IRQ_ENCODER			(1<<0)
+
+#define SOLO_CHIP_OPTION			0x001C
+#define   SOLO_CHIP_ID_MASK			0x00000007
+
+#define SOLO_PLL_CONFIG				0x0020 /* 6110 Only */
+
+#define SOLO_EEPROM_CTRL			0x0060
+#define	  SOLO_EEPROM_ACCESS_EN			(1<<7)
+#define	  SOLO_EEPROM_CS			(1<<3)
+#define	  SOLO_EEPROM_CLK			(1<<2)
+#define	  SOLO_EEPROM_DO			(1<<1)
+#define	  SOLO_EEPROM_DI			(1<<0)
+#define	  SOLO_EEPROM_ENABLE (SOLO_EEPROM_ACCESS_EN | SOLO_EEPROM_CS)
+
+#define SOLO_PCI_ERR				0x0070
+#define   SOLO_PCI_ERR_FATAL			0x00000001
+#define   SOLO_PCI_ERR_PARITY			0x00000002
+#define   SOLO_PCI_ERR_TARGET			0x00000004
+#define   SOLO_PCI_ERR_TIMEOUT			0x00000008
+#define   SOLO_PCI_ERR_P2M			0x00000010
+#define   SOLO_PCI_ERR_ATA			0x00000020
+#define   SOLO_PCI_ERR_P2M_DESC			0x00000040
+#define   SOLO_PCI_ERR_FSM0(__s)		(((__s) >> 16) & 0x0f)
+#define   SOLO_PCI_ERR_FSM1(__s)		(((__s) >> 20) & 0x0f)
+#define   SOLO_PCI_ERR_FSM2(__s)		(((__s) >> 24) & 0x1f)
+
+#define SOLO_P2M_BASE				0x0080
+
+#define SOLO_P2M_CONFIG(n)			(0x0080 + ((n)*0x20))
+#define	  SOLO_P2M_DMA_INTERVAL(n)		((n)<<6)/* N*32 clocks */
+#define	  SOLO_P2M_CSC_BYTE_REORDER		(1<<5)	/* BGR -> RGB */
+/* 0:r=[14:10] g=[9:5] b=[4:0], 1:r=[15:11] g=[10:5] b=[4:0] */
+#define	  SOLO_P2M_CSC_16BIT_565		(1<<4)
+#define	  SOLO_P2M_UV_SWAP			(1<<3)
+#define	  SOLO_P2M_PCI_MASTER_MODE		(1<<2)
+#define	  SOLO_P2M_DESC_INTR_OPT		(1<<1)	/* 1:Empty, 0:Each */
+#define	  SOLO_P2M_DESC_MODE			(1<<0)
+
+#define SOLO_P2M_DES_ADR(n)			(0x0084 + ((n)*0x20))
+
+#define SOLO_P2M_DESC_ID(n)			(0x0088 + ((n)*0x20))
+#define	  SOLO_P2M_UPDATE_ID(n)			((n)<<0)
+
+#define SOLO_P2M_STATUS(n)			(0x008C + ((n)*0x20))
+#define	  SOLO_P2M_COMMAND_DONE			(1<<8)
+#define	  SOLO_P2M_CURRENT_ID(stat)		(0xff & (stat))
+
+#define SOLO_P2M_CONTROL(n)			(0x0090 + ((n)*0x20))
+#define	  SOLO_P2M_PCI_INC(n)			((n)<<20)
+#define	  SOLO_P2M_REPEAT(n)			((n)<<10)
+/* 0:512, 1:256, 2:128, 3:64, 4:32, 5:128(2page) */
+#define	  SOLO_P2M_BURST_SIZE(n)		((n)<<7)
+#define	    SOLO_P2M_BURST_512			0
+#define	    SOLO_P2M_BURST_256			1
+#define	    SOLO_P2M_BURST_128			2
+#define	    SOLO_P2M_BURST_64			3
+#define	    SOLO_P2M_BURST_32			4
+#define	  SOLO_P2M_CSC_16BIT			(1<<6)	/* 0:24bit, 1:16bit */
+/* 0:Y[0]<-0(OFF), 1:Y[0]<-1(ON), 2:Y[0]<-G[0], 3:Y[0]<-Bit[15] */
+#define	  SOLO_P2M_ALPHA_MODE(n)		((n)<<4)
+#define	  SOLO_P2M_CSC_ON			(1<<3)
+#define	  SOLO_P2M_INTERRUPT_REQ		(1<<2)
+#define	  SOLO_P2M_WRITE			(1<<1)
+#define	  SOLO_P2M_TRANS_ON			(1<<0)
+
+#define SOLO_P2M_EXT_CFG(n)			(0x0094 + ((n)*0x20))
+#define	  SOLO_P2M_EXT_INC(n)			((n)<<20)
+#define	  SOLO_P2M_COPY_SIZE(n)			((n)<<0)
+
+#define SOLO_P2M_TAR_ADR(n)			(0x0098 + ((n)*0x20))
+
+#define SOLO_P2M_EXT_ADR(n)			(0x009C + ((n)*0x20))
+
+#define SOLO_P2M_BUFFER(i)			(0x2000 + ((i)*4))
+
+#define SOLO_VI_CH_SWITCH_0			0x0100
+#define SOLO_VI_CH_SWITCH_1			0x0104
+#define SOLO_VI_CH_SWITCH_2			0x0108
+
+#define	SOLO_VI_CH_ENA				0x010C
+#define	SOLO_VI_CH_FORMAT			0x0110
+#define	  SOLO_VI_FD_SEL_MASK(n)		((n)<<16)
+#define	  SOLO_VI_PROG_MASK(n)			((n)<<0)
+
+#define SOLO_VI_FMT_CFG				0x0114
+#define	  SOLO_VI_FMT_CHECK_VCOUNT		(1<<31)
+#define	  SOLO_VI_FMT_CHECK_HCOUNT		(1<<30)
+#define   SOLO_VI_FMT_TEST_SIGNAL		(1<<28)
+
+#define	SOLO_VI_PAGE_SW				0x0118
+#define	  SOLO_FI_INV_DISP_LIVE(n)		((n)<<8)
+#define	  SOLO_FI_INV_DISP_OUT(n)		((n)<<7)
+#define	  SOLO_DISP_SYNC_FI(n)			((n)<<6)
+#define	  SOLO_PIP_PAGE_ADD(n)			((n)<<3)
+#define	  SOLO_NORMAL_PAGE_ADD(n)		((n)<<0)
+
+#define	SOLO_VI_ACT_I_P				0x011C
+#define	SOLO_VI_ACT_I_S				0x0120
+#define	SOLO_VI_ACT_P				0x0124
+#define	  SOLO_VI_FI_INVERT			(1<<31)
+#define	  SOLO_VI_H_START(n)			((n)<<21)
+#define	  SOLO_VI_V_START(n)			((n)<<11)
+#define	  SOLO_VI_V_STOP(n)			((n)<<0)
+
+#define SOLO_VI_STATUS0				0x0128
+#define   SOLO_VI_STATUS0_PAGE(__n)		((__n) & 0x07)
+#define SOLO_VI_STATUS1				0x012C
+
+/* XXX: Might be better off in kernel level disp.h */
+#define DISP_PAGE(stat)				((stat) & 0x07)
+
+#define SOLO_VI_PB_CONFIG			0x0130
+#define	  SOLO_VI_PB_USER_MODE			(1<<1)
+#define	  SOLO_VI_PB_PAL			(1<<0)
+#define SOLO_VI_PB_RANGE_HV			0x0134
+#define	  SOLO_VI_PB_HSIZE(h)			((h)<<12)
+#define	  SOLO_VI_PB_VSIZE(v)			((v)<<0)
+#define SOLO_VI_PB_ACT_H			0x0138
+#define	  SOLO_VI_PB_HSTART(n)			((n)<<12)
+#define	  SOLO_VI_PB_HSTOP(n)			((n)<<0)
+#define SOLO_VI_PB_ACT_V			0x013C
+#define	  SOLO_VI_PB_VSTART(n)			((n)<<12)
+#define	  SOLO_VI_PB_VSTOP(n)			((n)<<0)
+
+#define	SOLO_VI_MOSAIC(ch)			(0x0140 + ((ch)*4))
+#define	  SOLO_VI_MOSAIC_SX(x)			((x)<<24)
+#define	  SOLO_VI_MOSAIC_EX(x)			((x)<<16)
+#define	  SOLO_VI_MOSAIC_SY(x)			((x)<<8)
+#define	  SOLO_VI_MOSAIC_EY(x)			((x)<<0)
+
+#define	SOLO_VI_WIN_CTRL0(ch)			(0x0180 + ((ch)*4))
+#define	SOLO_VI_WIN_CTRL1(ch)			(0x01C0 + ((ch)*4))
+
+#define	  SOLO_VI_WIN_CHANNEL(n)		((n)<<28)
+
+#define	  SOLO_VI_WIN_PIP(n)			((n)<<27)
+#define	  SOLO_VI_WIN_SCALE(n)			((n)<<24)
+
+#define	  SOLO_VI_WIN_SX(x)			((x)<<12)
+#define	  SOLO_VI_WIN_EX(x)			((x)<<0)
+
+#define	  SOLO_VI_WIN_SY(x)			((x)<<12)
+#define	  SOLO_VI_WIN_EY(x)			((x)<<0)
+
+#define	SOLO_VI_WIN_ON(ch)			(0x0200 + ((ch)*4))
+
+#define SOLO_VI_WIN_SW				0x0240
+#define SOLO_VI_WIN_LIVE_AUTO_MUTE		0x0244
+
+#define	SOLO_VI_MOT_ADR				0x0260
+#define	  SOLO_VI_MOTION_EN(mask)		((mask)<<16)
+#define	SOLO_VI_MOT_CTRL			0x0264
+#define	  SOLO_VI_MOTION_FRAME_COUNT(n)		((n)<<24)
+#define	  SOLO_VI_MOTION_SAMPLE_LENGTH(n)	((n)<<16)
+#define	  SOLO_VI_MOTION_INTR_START_STOP	(1<<15)
+#define	  SOLO_VI_MOTION_FREEZE_DATA		(1<<14)
+#define	  SOLO_VI_MOTION_SAMPLE_COUNT(n)	((n)<<0)
+#define SOLO_VI_MOT_CLEAR			0x0268
+#define SOLO_VI_MOT_STATUS			0x026C
+#define	  SOLO_VI_MOTION_CNT(n)			((n)<<0)
+#define SOLO_VI_MOTION_BORDER			0x0270
+#define SOLO_VI_MOTION_BAR			0x0274
+#define	  SOLO_VI_MOTION_Y_SET			(1<<29)
+#define	  SOLO_VI_MOTION_Y_ADD			(1<<28)
+#define	  SOLO_VI_MOTION_CB_SET			(1<<27)
+#define	  SOLO_VI_MOTION_CB_ADD			(1<<26)
+#define	  SOLO_VI_MOTION_CR_SET			(1<<25)
+#define	  SOLO_VI_MOTION_CR_ADD			(1<<24)
+#define	  SOLO_VI_MOTION_Y_VALUE(v)		((v)<<16)
+#define	  SOLO_VI_MOTION_CB_VALUE(v)		((v)<<8)
+#define	  SOLO_VI_MOTION_CR_VALUE(v)		((v)<<0)
+
+#define	SOLO_VO_FMT_ENC				0x0300
+#define	  SOLO_VO_SCAN_MODE_PROGRESSIVE		(1<<31)
+#define	  SOLO_VO_FMT_TYPE_PAL			(1<<30)
+#define   SOLO_VO_FMT_TYPE_NTSC			0
+#define	  SOLO_VO_USER_SET			(1<<29)
+
+#define	  SOLO_VO_FI_CHANGE			(1<<20)
+#define	  SOLO_VO_USER_COLOR_SET_VSYNC		(1<<19)
+#define	  SOLO_VO_USER_COLOR_SET_HSYNC		(1<<18)
+#define	  SOLO_VO_USER_COLOR_SET_NAH		(1<<17)
+#define	  SOLO_VO_USER_COLOR_SET_NAV		(1<<16)
+#define	  SOLO_VO_NA_COLOR_Y(Y)			((Y)<<8)
+#define	  SOLO_VO_NA_COLOR_CB(CB)		(((CB)/16)<<4)
+#define	  SOLO_VO_NA_COLOR_CR(CR)		(((CR)/16)<<0)
+
+#define	SOLO_VO_ACT_H				0x0304
+#define	  SOLO_VO_H_BLANK(n)			((n)<<22)
+#define	  SOLO_VO_H_START(n)			((n)<<11)
+#define	  SOLO_VO_H_STOP(n)			((n)<<0)
+
+#define	SOLO_VO_ACT_V				0x0308
+#define	  SOLO_VO_V_BLANK(n)			((n)<<22)
+#define	  SOLO_VO_V_START(n)			((n)<<11)
+#define	  SOLO_VO_V_STOP(n)			((n)<<0)
+
+#define	SOLO_VO_RANGE_HV			0x030C
+#define	  SOLO_VO_SYNC_INVERT			(1<<24)
+#define	  SOLO_VO_HSYNC_INVERT			(1<<23)
+#define	  SOLO_VO_VSYNC_INVERT			(1<<22)
+#define	  SOLO_VO_H_LEN(n)			((n)<<11)
+#define	  SOLO_VO_V_LEN(n)			((n)<<0)
+
+#define	SOLO_VO_DISP_CTRL			0x0310
+#define	  SOLO_VO_DISP_ON			(1<<31)
+#define	  SOLO_VO_DISP_ERASE_COUNT(n)		((n&0xf)<<24)
+#define	  SOLO_VO_DISP_DOUBLE_SCAN		(1<<22)
+#define	  SOLO_VO_DISP_SINGLE_PAGE		(1<<21)
+#define	  SOLO_VO_DISP_BASE(n)			(((n)>>16) & 0xffff)
+
+#define SOLO_VO_DISP_ERASE			0x0314
+#define	  SOLO_VO_DISP_ERASE_ON			(1<<0)
+
+#define	SOLO_VO_ZOOM_CTRL			0x0318
+#define	  SOLO_VO_ZOOM_VER_ON			(1<<24)
+#define	  SOLO_VO_ZOOM_HOR_ON			(1<<23)
+#define	  SOLO_VO_ZOOM_V_COMP			(1<<22)
+#define	  SOLO_VO_ZOOM_SX(h)			(((h)/2)<<11)
+#define	  SOLO_VO_ZOOM_SY(v)			(((v)/2)<<0)
+
+#define SOLO_VO_FREEZE_CTRL			0x031C
+#define	  SOLO_VO_FREEZE_ON			(1<<1)
+#define	  SOLO_VO_FREEZE_INTERPOLATION		(1<<0)
+
+#define	SOLO_VO_BKG_COLOR			0x0320
+#define	  SOLO_BG_Y(y)				((y)<<16)
+#define	  SOLO_BG_U(u)				((u)<<8)
+#define	  SOLO_BG_V(v)				((v)<<0)
+
+#define	SOLO_VO_DEINTERLACE			0x0324
+#define	  SOLO_VO_DEINTERLACE_THRESHOLD(n)	((n)<<8)
+#define	  SOLO_VO_DEINTERLACE_EDGE_VALUE(n)	((n)<<0)
+
+#define SOLO_VO_BORDER_LINE_COLOR		0x0330
+#define SOLO_VO_BORDER_FILL_COLOR		0x0334
+#define SOLO_VO_BORDER_LINE_MASK		0x0338
+#define SOLO_VO_BORDER_FILL_MASK		0x033c
+
+#define SOLO_VO_BORDER_X(n)			(0x0340+((n)*4))
+#define SOLO_VO_BORDER_Y(n)			(0x0354+((n)*4))
+
+#define SOLO_VO_CELL_EXT_SET			0x0368
+#define SOLO_VO_CELL_EXT_START			0x036c
+#define SOLO_VO_CELL_EXT_STOP			0x0370
+
+#define SOLO_VO_CELL_EXT_SET2			0x0374
+#define SOLO_VO_CELL_EXT_START2			0x0378
+#define SOLO_VO_CELL_EXT_STOP2			0x037c
+
+#define SOLO_VO_RECTANGLE_CTRL(n)		(0x0368+((n)*12))
+#define SOLO_VO_RECTANGLE_START(n)		(0x036c+((n)*12))
+#define SOLO_VO_RECTANGLE_STOP(n)		(0x0370+((n)*12))
+
+#define SOLO_VO_CURSOR_POS			(0x0380)
+#define SOLO_VO_CURSOR_CLR			(0x0384)
+#define SOLO_VO_CURSOR_CLR2			(0x0388)
+#define SOLO_VO_CURSOR_MASK(id)			(0x0390+((id)*4))
+
+#define SOLO_VO_EXPANSION(id)			(0x0250+((id)*4))
+
+#define	SOLO_OSG_CONFIG				0x03E0
+#define	  SOLO_VO_OSG_ON			(1<<31)
+#define	  SOLO_VO_OSG_COLOR_MUTE		(1<<28)
+#define	  SOLO_VO_OSG_ALPHA_RATE(n)		((n)<<22)
+#define	  SOLO_VO_OSG_ALPHA_BG_RATE(n)		((n)<<16)
+#define	  SOLO_VO_OSG_BASE(offset)		(((offset)>>16)&0xffff)
+
+#define SOLO_OSG_ERASE				0x03E4
+#define	  SOLO_OSG_ERASE_ON			(0x80)
+#define	  SOLO_OSG_ERASE_OFF			(0x00)
+
+#define SOLO_VO_OSG_BLINK			0x03E8
+#define	  SOLO_VO_OSG_BLINK_ON			(1<<1)
+#define	  SOLO_VO_OSG_BLINK_INTREVAL18		(1<<0)
+
+#define SOLO_CAP_BASE				0x0400
+#define	  SOLO_CAP_MAX_PAGE(n)			((n)<<16)
+#define	  SOLO_CAP_BASE_ADDR(n)			((n)<<0)
+#define SOLO_CAP_BTW				0x0404
+#define	  SOLO_CAP_PROG_BANDWIDTH(n)		((n)<<8)
+#define	  SOLO_CAP_MAX_BANDWIDTH(n)		((n)<<0)
+
+#define SOLO_DIM_SCALE1				0x0408
+#define SOLO_DIM_SCALE2				0x040C
+#define SOLO_DIM_SCALE3				0x0410
+#define SOLO_DIM_SCALE4				0x0414
+#define SOLO_DIM_SCALE5				0x0418
+#define	  SOLO_DIM_V_MB_NUM_FRAME(n)		((n)<<16)
+#define	  SOLO_DIM_V_MB_NUM_FIELD(n)		((n)<<8)
+#define	  SOLO_DIM_H_MB_NUM(n)			((n)<<0)
+
+#define SOLO_DIM_PROG				0x041C
+#define SOLO_CAP_STATUS				0x0420
+
+#define SOLO_CAP_CH_SCALE(ch)			(0x0440+((ch)*4))
+#define SOLO_CAP_CH_COMP_ENA_E(ch)		(0x0480+((ch)*4))
+#define SOLO_CAP_CH_INTV(ch)			(0x04C0+((ch)*4))
+#define SOLO_CAP_CH_INTV_E(ch)			(0x0500+((ch)*4))
+
+
+#define SOLO_VE_CFG0				0x0610
+#define	  SOLO_VE_TWO_PAGE_MODE			(1<<31)
+#define	  SOLO_VE_INTR_CTRL(n)			((n)<<24)
+#define	  SOLO_VE_BLOCK_SIZE(n)			((n)<<16)
+#define	  SOLO_VE_BLOCK_BASE(n)			((n)<<0)
+
+#define SOLO_VE_CFG1				0x0614
+#define	  SOLO_VE_BYTE_ALIGN(n)			((n)<<24)
+#define	  SOLO_VE_INSERT_INDEX			(1<<18)
+#define	  SOLO_VE_MOTION_MODE(n)		((n)<<16)
+#define	  SOLO_VE_MOTION_BASE(n)		((n)<<0)
+#define   SOLO_VE_MPEG_SIZE_H(n)		((n)<<28) /* 6110 Only */
+#define   SOLO_VE_JPEG_SIZE_H(n)		((n)<<20) /* 6110 Only */
+#define   SOLO_VE_INSERT_INDEX_JPEG		(1<<19)   /* 6110 Only */
+
+#define SOLO_VE_WMRK_POLY			0x061C
+#define SOLO_VE_VMRK_INIT_KEY			0x0620
+#define SOLO_VE_WMRK_STRL			0x0624
+#define SOLO_VE_ENCRYP_POLY			0x0628
+#define SOLO_VE_ENCRYP_INIT			0x062C
+#define SOLO_VE_ATTR				0x0630
+#define	  SOLO_VE_LITTLE_ENDIAN			(1<<31)
+#define	  SOLO_COMP_ATTR_RN			(1<<30)
+#define	  SOLO_COMP_ATTR_FCODE(n)		((n)<<27)
+#define	  SOLO_COMP_TIME_INC(n)			((n)<<25)
+#define	  SOLO_COMP_TIME_WIDTH(n)		((n)<<21)
+#define	  SOLO_DCT_INTERVAL(n)			((n)<<16)
+#define SOLO_VE_COMPT_MOT			0x0634 /* 6110 Only */
+
+#define SOLO_VE_STATE(n)			(0x0640+((n)*4))
+
+#define SOLO_VE_JPEG_QP_TBL			0x0670
+#define SOLO_VE_JPEG_QP_CH_L			0x0674
+#define SOLO_VE_JPEG_QP_CH_H			0x0678
+#define SOLO_VE_JPEG_CFG			0x067C
+#define SOLO_VE_JPEG_CTRL			0x0680
+#define SOLO_VE_CODE_ENCRYPT			0x0684 /* 6110 Only */
+#define SOLO_VE_JPEG_CFG1			0x0688 /* 6110 Only */
+#define SOLO_VE_WMRK_ENABLE			0x068C /* 6110 Only */
+#define SOLO_VE_OSD_CH				0x0690
+#define SOLO_VE_OSD_BASE			0x0694
+#define SOLO_VE_OSD_CLR				0x0698
+#define SOLO_VE_OSD_OPT				0x069C
+#define   SOLO_VE_OSD_V_DOUBLE			(1<<16) /* 6110 Only */
+#define   SOLO_VE_OSD_H_SHADOW			(1<<15)
+#define   SOLO_VE_OSD_V_SHADOW			(1<<14)
+#define   SOLO_VE_OSD_H_OFFSET(n)		((n & 0x7f)<<7)
+#define   SOLO_VE_OSD_V_OFFSET(n)		(n & 0x7f)
+
+#define SOLO_VE_CH_INTL(ch)			(0x0700+((ch)*4))
+#define SOLO_VE_CH_MOT(ch)			(0x0740+((ch)*4))
+#define SOLO_VE_CH_QP(ch)			(0x0780+((ch)*4))
+#define SOLO_VE_CH_QP_E(ch)			(0x07C0+((ch)*4))
+#define SOLO_VE_CH_GOP(ch)			(0x0800+((ch)*4))
+#define SOLO_VE_CH_GOP_E(ch)			(0x0840+((ch)*4))
+#define SOLO_VE_CH_REF_BASE(ch)			(0x0880+((ch)*4))
+#define SOLO_VE_CH_REF_BASE_E(ch)		(0x08C0+((ch)*4))
+
+#define SOLO_VE_MPEG4_QUE(n)			(0x0A00+((n)*8))
+#define SOLO_VE_JPEG_QUE(n)			(0x0A04+((n)*8))
+
+#define SOLO_VD_CFG0				0x0900
+#define	  SOLO_VD_CFG_NO_WRITE_NO_WINDOW	(1<<24)
+#define	  SOLO_VD_CFG_BUSY_WIAT_CODE		(1<<23)
+#define	  SOLO_VD_CFG_BUSY_WIAT_REF		(1<<22)
+#define	  SOLO_VD_CFG_BUSY_WIAT_RES		(1<<21)
+#define	  SOLO_VD_CFG_BUSY_WIAT_MS		(1<<20)
+#define	  SOLO_VD_CFG_SINGLE_MODE		(1<<18)
+#define	  SOLO_VD_CFG_SCAL_MANUAL		(1<<17)
+#define	  SOLO_VD_CFG_USER_PAGE_CTRL		(1<<16)
+#define	  SOLO_VD_CFG_LITTLE_ENDIAN		(1<<15)
+#define	  SOLO_VD_CFG_START_FI			(1<<14)
+#define	  SOLO_VD_CFG_ERR_LOCK			(1<<13)
+#define	  SOLO_VD_CFG_ERR_INT_ENA		(1<<12)
+#define	  SOLO_VD_CFG_TIME_WIDTH(n)		((n)<<8)
+#define	  SOLO_VD_CFG_DCT_INTERVAL(n)		((n)<<0)
+
+#define SOLO_VD_CFG1				0x0904
+
+#define	SOLO_VD_DEINTERLACE			0x0908
+#define	  SOLO_VD_DEINTERLACE_THRESHOLD(n)	((n)<<8)
+#define	  SOLO_VD_DEINTERLACE_EDGE_VALUE(n)	((n)<<0)
+
+#define SOLO_VD_CODE_ADR			0x090C
+
+#define SOLO_VD_CTRL				0x0910
+#define	  SOLO_VD_OPER_ON			(1<<31)
+#define	  SOLO_VD_MAX_ITEM(n)			((n)<<0)
+
+#define SOLO_VD_STATUS0				0x0920
+#define	  SOLO_VD_STATUS0_INTR_ACK		(1<<22)
+#define	  SOLO_VD_STATUS0_INTR_EMPTY		(1<<21)
+#define	  SOLO_VD_STATUS0_INTR_ERR		(1<<20)
+
+#define SOLO_VD_STATUS1				0x0924
+
+#define SOLO_VD_IDX0				0x0930
+#define	  SOLO_VD_IDX_INTERLACE			(1<<30)
+#define	  SOLO_VD_IDX_CHANNEL(n)		((n)<<24)
+#define	  SOLO_VD_IDX_SIZE(n)			((n)<<0)
+
+#define SOLO_VD_IDX1				0x0934
+#define	  SOLO_VD_IDX_SRC_SCALE(n)		((n)<<28)
+#define	  SOLO_VD_IDX_WINDOW(n)			((n)<<24)
+#define	  SOLO_VD_IDX_DEINTERLACE		(1<<16)
+#define	  SOLO_VD_IDX_H_BLOCK(n)		((n)<<8)
+#define	  SOLO_VD_IDX_V_BLOCK(n)		((n)<<0)
+
+#define SOLO_VD_IDX2				0x0938
+#define	  SOLO_VD_IDX_REF_BASE_SIDE		(1<<31)
+#define	  SOLO_VD_IDX_REF_BASE(n)		(((n)>>16)&0xffff)
+
+#define SOLO_VD_IDX3				0x093C
+#define	  SOLO_VD_IDX_DISP_SCALE(n)		((n)<<28)
+#define	  SOLO_VD_IDX_INTERLACE_WR		(1<<27)
+#define	  SOLO_VD_IDX_INTERPOL			(1<<26)
+#define	  SOLO_VD_IDX_HOR2X			(1<<25)
+#define	  SOLO_VD_IDX_OFFSET_X(n)		((n)<<12)
+#define	  SOLO_VD_IDX_OFFSET_Y(n)		((n)<<0)
+
+#define SOLO_VD_IDX4				0x0940
+#define	  SOLO_VD_IDX_DEC_WR_PAGE(n)		((n)<<8)
+#define	  SOLO_VD_IDX_DISP_RD_PAGE(n)		((n)<<0)
+
+#define SOLO_VD_WR_PAGE(n)			(0x03F0 + ((n) * 4))
+
+
+#define SOLO_GPIO_CONFIG_0			0x0B00
+#define SOLO_GPIO_CONFIG_1			0x0B04
+#define SOLO_GPIO_DATA_OUT			0x0B08
+#define SOLO_GPIO_DATA_IN			0x0B0C
+#define SOLO_GPIO_INT_ACK_STA			0x0B10
+#define SOLO_GPIO_INT_ENA			0x0B14
+#define SOLO_GPIO_INT_CFG_0			0x0B18
+#define SOLO_GPIO_INT_CFG_1			0x0B1C
+
+
+#define SOLO_IIC_CFG				0x0B20
+#define	  SOLO_IIC_ENABLE			(1<<8)
+#define	  SOLO_IIC_PRESCALE(n)			((n)<<0)
+
+#define SOLO_IIC_CTRL				0x0B24
+#define	  SOLO_IIC_AUTO_CLEAR			(1<<20)
+#define	  SOLO_IIC_STATE_RX_ACK			(1<<19)
+#define	  SOLO_IIC_STATE_BUSY			(1<<18)
+#define	  SOLO_IIC_STATE_SIG_ERR		(1<<17)
+#define	  SOLO_IIC_STATE_TRNS			(1<<16)
+#define	  SOLO_IIC_CH_SET(n)			((n)<<5)
+#define	  SOLO_IIC_ACK_EN			(1<<4)
+#define	  SOLO_IIC_START			(1<<3)
+#define	  SOLO_IIC_STOP				(1<<2)
+#define	  SOLO_IIC_READ				(1<<1)
+#define	  SOLO_IIC_WRITE			(1<<0)
+
+#define SOLO_IIC_TXD				0x0B28
+#define SOLO_IIC_RXD				0x0B2C
+
+/*
+ *	UART REGISTER
+ */
+#define SOLO_UART_CONTROL(n)			(0x0BA0 + ((n)*0x20))
+#define	  SOLO_UART_CLK_DIV(n)			((n)<<24)
+#define	  SOLO_MODEM_CTRL_EN			(1<<20)
+#define	  SOLO_PARITY_ERROR_DROP		(1<<18)
+#define	  SOLO_IRQ_ERR_EN			(1<<17)
+#define	  SOLO_IRQ_RX_EN			(1<<16)
+#define	  SOLO_IRQ_TX_EN			(1<<15)
+#define	  SOLO_RX_EN				(1<<14)
+#define	  SOLO_TX_EN				(1<<13)
+#define	  SOLO_UART_HALF_DUPLEX			(1<<12)
+#define	  SOLO_UART_LOOPBACK			(1<<11)
+
+#define	  SOLO_BAUDRATE_230400			((0<<9)|(0<<6))
+#define	  SOLO_BAUDRATE_115200			((0<<9)|(1<<6))
+#define	  SOLO_BAUDRATE_57600			((0<<9)|(2<<6))
+#define	  SOLO_BAUDRATE_38400			((0<<9)|(3<<6))
+#define	  SOLO_BAUDRATE_19200			((0<<9)|(4<<6))
+#define	  SOLO_BAUDRATE_9600			((0<<9)|(5<<6))
+#define	  SOLO_BAUDRATE_4800			((0<<9)|(6<<6))
+#define	  SOLO_BAUDRATE_2400			((1<<9)|(6<<6))
+#define	  SOLO_BAUDRATE_1200			((2<<9)|(6<<6))
+#define	  SOLO_BAUDRATE_300			((3<<9)|(6<<6))
+
+#define	  SOLO_UART_DATA_BIT_8			(3<<4)
+#define	  SOLO_UART_DATA_BIT_7			(2<<4)
+#define	  SOLO_UART_DATA_BIT_6			(1<<4)
+#define	  SOLO_UART_DATA_BIT_5			(0<<4)
+
+#define	  SOLO_UART_STOP_BIT_1			(0<<2)
+#define	  SOLO_UART_STOP_BIT_2			(1<<2)
+
+#define	  SOLO_UART_PARITY_NONE			(0<<0)
+#define	  SOLO_UART_PARITY_EVEN			(2<<0)
+#define	  SOLO_UART_PARITY_ODD			(3<<0)
+
+#define SOLO_UART_STATUS(n)			(0x0BA4 + ((n)*0x20))
+#define	  SOLO_UART_CTS				(1<<15)
+#define	  SOLO_UART_RX_BUSY			(1<<14)
+#define	  SOLO_UART_OVERRUN			(1<<13)
+#define	  SOLO_UART_FRAME_ERR			(1<<12)
+#define	  SOLO_UART_PARITY_ERR			(1<<11)
+#define	  SOLO_UART_TX_BUSY			(1<<5)
+
+#define	  SOLO_UART_RX_BUFF_CNT(stat)		(((stat)>>6) & 0x1f)
+#define	  SOLO_UART_RX_BUFF_SIZE		8
+#define	  SOLO_UART_TX_BUFF_CNT(stat)		(((stat)>>0) & 0x1f)
+#define	  SOLO_UART_TX_BUFF_SIZE		8
+
+#define SOLO_UART_TX_DATA(n)			(0x0BA8 + ((n)*0x20))
+#define	  SOLO_UART_TX_DATA_PUSH		(1<<8)
+#define SOLO_UART_RX_DATA(n)			(0x0BAC + ((n)*0x20))
+#define	  SOLO_UART_RX_DATA_POP			(1<<8)
+
+#define SOLO_TIMER_CLOCK_NUM			0x0be0
+#define SOLO_TIMER_USEC				0x0be8
+#define SOLO_TIMER_SEC				0x0bec
+#define SOLO_TIMER_USEC_LSB			0x0d20 /* 6110 Only */
+
+#define SOLO_AUDIO_CONTROL			0x0D00
+#define	  SOLO_AUDIO_ENABLE			(1<<31)
+#define	  SOLO_AUDIO_MASTER_MODE		(1<<30)
+#define	  SOLO_AUDIO_I2S_MODE			(1<<29)
+#define	  SOLO_AUDIO_I2S_LR_SWAP		(1<<27)
+#define	  SOLO_AUDIO_I2S_8BIT			(1<<26)
+#define	  SOLO_AUDIO_I2S_MULTI(n)		((n)<<24)
+#define	  SOLO_AUDIO_MIX_9TO0			(1<<23)
+#define	  SOLO_AUDIO_DEC_9TO0_VOL(n)		((n)<<20)
+#define	  SOLO_AUDIO_MIX_19TO10			(1<<19)
+#define	  SOLO_AUDIO_DEC_19TO10_VOL(n)		((n)<<16)
+#define	  SOLO_AUDIO_MODE(n)			((n)<<0)
+#define SOLO_AUDIO_SAMPLE			0x0D04
+#define	  SOLO_AUDIO_EE_MODE_ON			(1<<30)
+#define	  SOLO_AUDIO_EE_ENC_CH(ch)		((ch)<<25)
+#define	  SOLO_AUDIO_BITRATE(n)			((n)<<16)
+#define	  SOLO_AUDIO_CLK_DIV(n)			((n)<<0)
+#define SOLO_AUDIO_FDMA_INTR			0x0D08
+#define	  SOLO_AUDIO_FDMA_INTERVAL(n)		((n)<<19)
+#define	  SOLO_AUDIO_INTR_ORDER(n)		((n)<<16)
+#define	  SOLO_AUDIO_FDMA_BASE(n)		((n)<<0)
+#define SOLO_AUDIO_EVOL_0			0x0D0C
+#define SOLO_AUDIO_EVOL_1			0x0D10
+#define	  SOLO_AUDIO_EVOL(ch, value)		((value)<<((ch)%10))
+#define SOLO_AUDIO_STA				0x0D14
+
+/*
+ * Watchdog configuration
+ */
+#define SOLO_WATCHDOG				0x0be4
+#define SOLO_WATCHDOG_SET(status, sec)		(status << 8 | (sec & 0xff))
+
+#endif /* __SOLO6X10_REGISTERS_H */
diff --git a/drivers/media/pci/solo6x10/solo6x10-tw28.c b/drivers/media/pci/solo6x10/solo6x10-tw28.c
new file mode 100644
index 0000000000000..edd0781ee4b51
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10-tw28.c
@@ -0,0 +1,871 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include "solo6x10.h"
+#include "solo6x10-tw28.h"
+
+#define DEFAULT_HDELAY_NTSC		(32 - 8)
+#define DEFAULT_HACTIVE_NTSC		(720 + 16)
+#define DEFAULT_VDELAY_NTSC		(7 - 2)
+#define DEFAULT_VACTIVE_NTSC		(240 + 4)
+
+#define DEFAULT_HDELAY_PAL		(32 + 4)
+#define DEFAULT_HACTIVE_PAL		(864-DEFAULT_HDELAY_PAL)
+#define DEFAULT_VDELAY_PAL		(6)
+#define DEFAULT_VACTIVE_PAL		(312-DEFAULT_VDELAY_PAL)
+
+
+static const u8 tbl_tw2864_ntsc_template[] = {
+	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
+	0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
+	0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
+	0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
+	0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
+	0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
+	0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
+	0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */
+	0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01,
+	0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */
+	0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
+	0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
+	0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
+	0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */
+	0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81,
+	0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
+	0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
+	0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
+	0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
+};
+
+static const u8 tbl_tw2864_pal_template[] = {
+	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */
+	0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
+	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */
+	0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
+	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */
+	0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
+	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */
+	0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
+	0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
+	0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
+	0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */
+	0x00, 0x28, 0x44, 0x44, 0xa0, 0x90, 0x5a, 0x01,
+	0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */
+	0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
+	0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
+	0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
+	0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */
+	0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81,
+	0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
+	0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
+	0x83, 0xb5, 0x09, 0x00, 0xa0, 0x00, 0x01, 0x20, /* 0xf0 */
+	0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
+};
+
+static const u8 tbl_tw2865_ntsc_template[] = {
+	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
+	0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
+	0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
+	0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+	0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
+	0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+	0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, /* 0x40 */
+	0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
+	0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
+	0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
+	0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
+	0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
+	0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
+	0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
+	0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, /* 0xa0 */
+	0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
+	0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
+	0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8,
+	0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
+	0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
+	0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
+	0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
+	0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
+	0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
+	0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
+	0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
+};
+
+static const u8 tbl_tw2865_pal_template[] = {
+	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */
+	0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
+	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */
+	0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
+	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */
+	0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
+	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */
+	0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
+	0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, /* 0x40 */
+	0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
+	0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
+	0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
+	0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
+	0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
+	0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
+	0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
+	0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, /* 0xa0 */
+	0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
+	0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
+	0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8,
+	0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
+	0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
+	0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
+	0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
+	0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
+	0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
+	0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, /* 0xf0 */
+	0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
+};
+
+#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
+
+static u8 tw_readbyte(struct solo_dev *solo_dev, int chip_id, u8 tw6x_off,
+		      u8 tw_off)
+{
+	if (is_tw286x(solo_dev, chip_id))
+		return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+					 TW_CHIP_OFFSET_ADDR(chip_id),
+					 tw6x_off);
+	else
+		return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+					 TW_CHIP_OFFSET_ADDR(chip_id),
+					 tw_off);
+}
+
+static void tw_writebyte(struct solo_dev *solo_dev, int chip_id,
+			 u8 tw6x_off, u8 tw_off, u8 val)
+{
+	if (is_tw286x(solo_dev, chip_id))
+		solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
+				   TW_CHIP_OFFSET_ADDR(chip_id),
+				   tw6x_off, val);
+	else
+		solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
+				   TW_CHIP_OFFSET_ADDR(chip_id),
+				   tw_off, val);
+}
+
+static void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off,
+				u8 val)
+{
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		u8 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, addr, off);
+
+		if (rval == val)
+			return;
+
+		solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, addr, off, val);
+		msleep_interruptible(1);
+	}
+
+/*	printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n", */
+/*		addr, off, val); */
+}
+
+static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr)
+{
+	u8 tbl_tw2865_common[256];
+	int i;
+
+	if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL)
+		memcpy(tbl_tw2865_common, tbl_tw2865_pal_template,
+		       sizeof(tbl_tw2865_common));
+	else
+		memcpy(tbl_tw2865_common, tbl_tw2865_ntsc_template,
+		       sizeof(tbl_tw2865_common));
+
+	/* ALINK Mode */
+	if (solo_dev->nr_chans == 4) {
+		tbl_tw2865_common[0xd2] = 0x01;
+		tbl_tw2865_common[0xcf] = 0x00;
+	} else if (solo_dev->nr_chans == 8) {
+		tbl_tw2865_common[0xd2] = 0x02;
+		if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+			tbl_tw2865_common[0xcf] = 0x80;
+	} else if (solo_dev->nr_chans == 16) {
+		tbl_tw2865_common[0xd2] = 0x03;
+		if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+			tbl_tw2865_common[0xcf] = 0x83;
+		else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
+			tbl_tw2865_common[0xcf] = 0x83;
+		else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
+			tbl_tw2865_common[0xcf] = 0x80;
+	}
+
+	for (i = 0; i < 0xff; i++) {
+		/* Skip read only registers */
+		switch (i) {
+		case 0xb8 ... 0xc1:
+		case 0xc4 ... 0xc7:
+		case 0xfd:
+			continue;
+		}
+		switch (i & ~0x30) {
+		case 0x00:
+		case 0x0c ... 0x0d:
+			continue;
+		}
+
+		tw_write_and_verify(solo_dev, dev_addr, i,
+				    tbl_tw2865_common[i]);
+	}
+
+	return 0;
+}
+
+static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr)
+{
+	u8 tbl_tw2864_common[256];
+	int i;
+
+	if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL)
+		memcpy(tbl_tw2864_common, tbl_tw2864_pal_template,
+		       sizeof(tbl_tw2864_common));
+	else
+		memcpy(tbl_tw2864_common, tbl_tw2864_ntsc_template,
+		       sizeof(tbl_tw2864_common));
+
+	if (solo_dev->tw2865 == 0) {
+		/* IRQ Mode */
+		if (solo_dev->nr_chans == 4) {
+			tbl_tw2864_common[0xd2] = 0x01;
+			tbl_tw2864_common[0xcf] = 0x00;
+		} else if (solo_dev->nr_chans == 8) {
+			tbl_tw2864_common[0xd2] = 0x02;
+			if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
+				tbl_tw2864_common[0xcf] = 0x43;
+			else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+				tbl_tw2864_common[0xcf] = 0x40;
+		} else if (solo_dev->nr_chans == 16) {
+			tbl_tw2864_common[0xd2] = 0x03;
+			if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
+				tbl_tw2864_common[0xcf] = 0x43;
+			else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+				tbl_tw2864_common[0xcf] = 0x43;
+			else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
+				tbl_tw2864_common[0xcf] = 0x43;
+			else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
+				tbl_tw2864_common[0xcf] = 0x40;
+		}
+	} else {
+		/* ALINK Mode. Assumes that the first tw28xx is a
+		 * 2865 and these are in cascade. */
+		for (i = 0; i <= 4; i++)
+			tbl_tw2864_common[0x08 | i << 4] = 0x12;
+
+		if (solo_dev->nr_chans == 8) {
+			tbl_tw2864_common[0xd2] = 0x02;
+			if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+				tbl_tw2864_common[0xcf] = 0x80;
+		} else if (solo_dev->nr_chans == 16) {
+			tbl_tw2864_common[0xd2] = 0x03;
+			if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+				tbl_tw2864_common[0xcf] = 0x83;
+			else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
+				tbl_tw2864_common[0xcf] = 0x83;
+			else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
+				tbl_tw2864_common[0xcf] = 0x80;
+		}
+	}
+
+	for (i = 0; i < 0xff; i++) {
+		/* Skip read only registers */
+		switch (i) {
+		case 0xb8 ... 0xc1:
+		case 0xfd:
+			continue;
+		}
+		switch (i & ~0x30) {
+		case 0x00:
+		case 0x0c:
+		case 0x0d:
+			continue;
+		}
+
+		tw_write_and_verify(solo_dev, dev_addr, i,
+				    tbl_tw2864_common[i]);
+	}
+
+	return 0;
+}
+
+static int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr)
+{
+	u8 tbl_ntsc_tw2815_common[] = {
+		0x00, 0xc8, 0x20, 0xd0, 0x06, 0xf0, 0x08, 0x80,
+		0x80, 0x80, 0x80, 0x02, 0x06, 0x00, 0x11,
+	};
+
+	u8 tbl_pal_tw2815_common[] = {
+		0x00, 0x88, 0x20, 0xd0, 0x05, 0x20, 0x28, 0x80,
+		0x80, 0x80, 0x80, 0x82, 0x06, 0x00, 0x11,
+	};
+
+	u8 tbl_tw2815_sfr[] = {
+		0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, /* 0x00 */
+		0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00,
+		0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, /* 0x10 */
+		0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00,
+		0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, /* 0x20 */
+		0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88,
+		0x88, 0x11, 0x00, 0x88, 0x88, 0x00,		/* 0x30 */
+	};
+	u8 *tbl_tw2815_common;
+	int i;
+	int ch;
+
+	tbl_ntsc_tw2815_common[0x06] = 0;
+
+	/* Horizontal Delay Control */
+	tbl_ntsc_tw2815_common[0x02] = DEFAULT_HDELAY_NTSC & 0xff;
+	tbl_ntsc_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_NTSC >> 8);
+
+	/* Horizontal Active Control */
+	tbl_ntsc_tw2815_common[0x03] = DEFAULT_HACTIVE_NTSC & 0xff;
+	tbl_ntsc_tw2815_common[0x06] |=
+		((0x03 & (DEFAULT_HACTIVE_NTSC >> 8)) << 2);
+
+	/* Vertical Delay Control */
+	tbl_ntsc_tw2815_common[0x04] = DEFAULT_VDELAY_NTSC & 0xff;
+	tbl_ntsc_tw2815_common[0x06] |=
+		((0x01 & (DEFAULT_VDELAY_NTSC >> 8)) << 4);
+
+	/* Vertical Active Control */
+	tbl_ntsc_tw2815_common[0x05] = DEFAULT_VACTIVE_NTSC & 0xff;
+	tbl_ntsc_tw2815_common[0x06] |=
+		((0x01 & (DEFAULT_VACTIVE_NTSC >> 8)) << 5);
+
+	tbl_pal_tw2815_common[0x06] = 0;
+
+	/* Horizontal Delay Control */
+	tbl_pal_tw2815_common[0x02] = DEFAULT_HDELAY_PAL & 0xff;
+	tbl_pal_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_PAL >> 8);
+
+	/* Horizontal Active Control */
+	tbl_pal_tw2815_common[0x03] = DEFAULT_HACTIVE_PAL & 0xff;
+	tbl_pal_tw2815_common[0x06] |=
+		((0x03 & (DEFAULT_HACTIVE_PAL >> 8)) << 2);
+
+	/* Vertical Delay Control */
+	tbl_pal_tw2815_common[0x04] = DEFAULT_VDELAY_PAL & 0xff;
+	tbl_pal_tw2815_common[0x06] |=
+		((0x01 & (DEFAULT_VDELAY_PAL >> 8)) << 4);
+
+	/* Vertical Active Control */
+	tbl_pal_tw2815_common[0x05] = DEFAULT_VACTIVE_PAL & 0xff;
+	tbl_pal_tw2815_common[0x06] |=
+		((0x01 & (DEFAULT_VACTIVE_PAL >> 8)) << 5);
+
+	tbl_tw2815_common =
+	    (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) ?
+	     tbl_ntsc_tw2815_common : tbl_pal_tw2815_common;
+
+	/* Dual ITU-R BT.656 format */
+	tbl_tw2815_common[0x0d] |= 0x04;
+
+	/* Audio configuration */
+	tbl_tw2815_sfr[0x62 - 0x40] &= ~(3 << 6);
+
+	if (solo_dev->nr_chans == 4) {
+		tbl_tw2815_sfr[0x63 - 0x40] |= 1;
+		tbl_tw2815_sfr[0x62 - 0x40] |= 3 << 6;
+	} else if (solo_dev->nr_chans == 8) {
+		tbl_tw2815_sfr[0x63 - 0x40] |= 2;
+		if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
+			tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
+		else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+			tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
+	} else if (solo_dev->nr_chans == 16) {
+		tbl_tw2815_sfr[0x63 - 0x40] |= 3;
+		if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
+			tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
+		else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+			tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
+		else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
+			tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
+		else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
+			tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
+	}
+
+	/* Output mode of R_ADATM pin (0 mixing, 1 record) */
+	/* tbl_tw2815_sfr[0x63 - 0x40] |= 0 << 2; */
+
+	/* 8KHz, used to be 16KHz, but changed for remote client compat */
+	tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 2;
+	tbl_tw2815_sfr[0x6c - 0x40] |= 0 << 2;
+
+	/* Playback of right channel */
+	tbl_tw2815_sfr[0x6c - 0x40] |= 1 << 5;
+
+	/* Reserved value (XXX ??) */
+	tbl_tw2815_sfr[0x5c - 0x40] |= 1 << 5;
+
+	/* Analog output gain and mix ratio playback on full */
+	tbl_tw2815_sfr[0x70 - 0x40] |= 0xff;
+	/* Select playback audio and mute all except */
+	tbl_tw2815_sfr[0x71 - 0x40] |= 0x10;
+	tbl_tw2815_sfr[0x6d - 0x40] |= 0x0f;
+
+	/* End of audio configuration */
+
+	for (ch = 0; ch < 4; ch++) {
+		tbl_tw2815_common[0x0d] &= ~3;
+		switch (ch) {
+		case 0:
+			tbl_tw2815_common[0x0d] |= 0x21;
+			break;
+		case 1:
+			tbl_tw2815_common[0x0d] |= 0x20;
+			break;
+		case 2:
+			tbl_tw2815_common[0x0d] |= 0x23;
+			break;
+		case 3:
+			tbl_tw2815_common[0x0d] |= 0x22;
+			break;
+		}
+
+		for (i = 0; i < 0x0f; i++) {
+			if (i == 0x00)
+				continue;	/* read-only */
+			solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
+					   dev_addr, (ch * 0x10) + i,
+					   tbl_tw2815_common[i]);
+		}
+	}
+
+	for (i = 0x40; i < 0x76; i++) {
+		/* Skip read-only and nop registers */
+		if (i == 0x40 || i == 0x59 || i == 0x5a ||
+		    i == 0x5d || i == 0x5e || i == 0x5f)
+			continue;
+
+		solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, dev_addr, i,
+				       tbl_tw2815_sfr[i - 0x40]);
+	}
+
+	return 0;
+}
+
+#define FIRST_ACTIVE_LINE	0x0008
+#define LAST_ACTIVE_LINE	0x0102
+
+static void saa712x_write_regs(struct solo_dev *dev, const uint8_t *vals,
+		int start, int n)
+{
+	for (; start < n; start++, vals++) {
+		/* Skip read-only registers */
+		switch (start) {
+		/* case 0x00 ... 0x25: */
+		case 0x2e ... 0x37:
+		case 0x60:
+		case 0x7d:
+			continue;
+		}
+		solo_i2c_writebyte(dev, SOLO_I2C_SAA, 0x46, start, *vals);
+	}
+}
+
+#define SAA712x_reg7c (0x80 | ((LAST_ACTIVE_LINE & 0x100) >> 2) \
+		| ((FIRST_ACTIVE_LINE & 0x100) >> 4))
+
+static void saa712x_setup(struct solo_dev *dev)
+{
+	const int reg_start = 0x26;
+	const uint8_t saa7128_regs_ntsc[] = {
+	/* :0x26 */
+		0x0d, 0x00,
+	/* :0x28 */
+		0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f,
+	/* :0x2e XXX: read-only */
+		0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* :0x38 */
+		0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* :0x40 */
+		0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
+		0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
+	/* :0x50 */
+		0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
+		0x02, 0x80, 0x71, 0x77, 0xa7, 0x67, 0x66, 0x2e,
+	/* :0x60 */
+		0x7b, 0x11, 0x4f, 0x1f, 0x7c, 0xf0, 0x21, 0x77,
+		0x41, 0x88, 0x41, 0x52, 0xed, 0x10, 0x10, 0x00,
+	/* :0x70 */
+		0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
+		0x00, 0x00, FIRST_ACTIVE_LINE, LAST_ACTIVE_LINE & 0xff,
+		SAA712x_reg7c, 0x00, 0xff, 0xff,
+	}, saa7128_regs_pal[] = {
+	/* :0x26 */
+		0x0d, 0x00,
+	/* :0x28 */
+		0xe1, 0x1d, 0x75, 0x3f, 0x06, 0x3f,
+	/* :0x2e XXX: read-only */
+		0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* :0x38 */
+		0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* :0x40 */
+		0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
+		0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
+	/* :0x50 */
+		0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
+		0x02, 0x80, 0x0f, 0x77, 0xa7, 0x67, 0x66, 0x2e,
+	/* :0x60 */
+		0x7b, 0x02, 0x35, 0xcb, 0x8a, 0x09, 0x2a, 0x77,
+		0x41, 0x88, 0x41, 0x52, 0xf1, 0x10, 0x20, 0x00,
+	/* :0x70 */
+		0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
+		0x00, 0x00, 0x12, 0x30,
+		SAA712x_reg7c | 0x40, 0x00, 0xff, 0xff,
+	};
+
+	if (dev->video_type == SOLO_VO_FMT_TYPE_PAL)
+		saa712x_write_regs(dev, saa7128_regs_pal, reg_start,
+				sizeof(saa7128_regs_pal));
+	else
+		saa712x_write_regs(dev, saa7128_regs_ntsc, reg_start,
+				sizeof(saa7128_regs_ntsc));
+}
+
+int solo_tw28_init(struct solo_dev *solo_dev)
+{
+	int i;
+	u8 value;
+
+	solo_dev->tw28_cnt = 0;
+
+	/* Detect techwell chip type(s) */
+	for (i = 0; i < solo_dev->nr_chans / 4; i++) {
+		value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+					  TW_CHIP_OFFSET_ADDR(i), 0xFF);
+
+		switch (value >> 3) {
+		case 0x18:
+			solo_dev->tw2865 |= 1 << i;
+			solo_dev->tw28_cnt++;
+			break;
+		case 0x0c:
+			solo_dev->tw2864 |= 1 << i;
+			solo_dev->tw28_cnt++;
+			break;
+		default:
+			value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+						  TW_CHIP_OFFSET_ADDR(i),
+						  0x59);
+			if ((value >> 3) == 0x04) {
+				solo_dev->tw2815 |= 1 << i;
+				solo_dev->tw28_cnt++;
+			}
+		}
+	}
+
+	if (solo_dev->tw28_cnt != (solo_dev->nr_chans >> 2)) {
+		dev_err(&solo_dev->pdev->dev,
+			"Could not initialize any techwell chips\n");
+		return -EINVAL;
+	}
+
+	saa712x_setup(solo_dev);
+
+	for (i = 0; i < solo_dev->tw28_cnt; i++) {
+		if ((solo_dev->tw2865 & (1 << i)))
+			tw2865_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
+		else if ((solo_dev->tw2864 & (1 << i)))
+			tw2864_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
+		else
+			tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
+	}
+
+	return 0;
+}
+
+/*
+ * We accessed the video status signal in the Techwell chip through
+ * iic/i2c because the video status reported by register REG_VI_STATUS1
+ * (address 0x012C) of the SOLO6010 chip doesn't give the correct video
+ * status signal values.
+ */
+int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch)
+{
+	u8 val, chip_num;
+
+	/* Get the right chip and on-chip channel */
+	chip_num = ch / 4;
+	ch %= 4;
+
+	val = tw_readbyte(solo_dev, chip_num, TW286x_AV_STAT_ADDR,
+			  TW_AV_STAT_ADDR) & 0x0f;
+
+	return val & (1 << ch) ? 1 : 0;
+}
+
+#if 0
+/* Status of audio from up to 4 techwell chips are combined into 1 variable.
+ * See techwell datasheet for details. */
+u16 tw28_get_audio_status(struct solo_dev *solo_dev)
+{
+	u8 val;
+	u16 status = 0;
+	int i;
+
+	for (i = 0; i < solo_dev->tw28_cnt; i++) {
+		val = (tw_readbyte(solo_dev, i, TW286x_AV_STAT_ADDR,
+				   TW_AV_STAT_ADDR) & 0xf0) >> 4;
+		status |= val << (i * 4);
+	}
+
+	return status;
+}
+#endif
+
+bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch)
+{
+	return is_tw286x(solo_dev, ch / 4);
+}
+
+int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
+		      s32 val)
+{
+	char sval;
+	u8 chip_num;
+
+	/* Get the right chip and on-chip channel */
+	chip_num = ch / 4;
+	ch %= 4;
+
+	if (val > 255 || val < 0)
+		return -ERANGE;
+
+	switch (ctrl) {
+	case V4L2_CID_SHARPNESS:
+		/* Only 286x has sharpness */
+		if (is_tw286x(solo_dev, chip_num)) {
+			u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+						 TW_CHIP_OFFSET_ADDR(chip_num),
+						 TW286x_SHARPNESS(chip_num));
+			v &= 0xf0;
+			v |= val;
+			solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
+					   TW_CHIP_OFFSET_ADDR(chip_num),
+					   TW286x_SHARPNESS(chip_num), v);
+		} else {
+			return -EINVAL;
+		}
+		break;
+
+	case V4L2_CID_HUE:
+		if (is_tw286x(solo_dev, chip_num))
+			sval = val - 128;
+		else
+			sval = (char)val;
+		tw_writebyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
+			     TW_HUE_ADDR(ch), sval);
+
+		break;
+
+	case V4L2_CID_SATURATION:
+		/* 286x chips have a U and V component for saturation */
+		if (is_tw286x(solo_dev, chip_num)) {
+			solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
+					   TW_CHIP_OFFSET_ADDR(chip_num),
+					   TW286x_SATURATIONU_ADDR(ch), val);
+		}
+		tw_writebyte(solo_dev, chip_num, TW286x_SATURATIONV_ADDR(ch),
+			     TW_SATURATION_ADDR(ch), val);
+
+		break;
+
+	case V4L2_CID_CONTRAST:
+		tw_writebyte(solo_dev, chip_num, TW286x_CONTRAST_ADDR(ch),
+			     TW_CONTRAST_ADDR(ch), val);
+		break;
+
+	case V4L2_CID_BRIGHTNESS:
+		if (is_tw286x(solo_dev, chip_num))
+			sval = val - 128;
+		else
+			sval = (char)val;
+		tw_writebyte(solo_dev, chip_num, TW286x_BRIGHTNESS_ADDR(ch),
+			     TW_BRIGHTNESS_ADDR(ch), sval);
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
+		      s32 *val)
+{
+	u8 rval, chip_num;
+
+	/* Get the right chip and on-chip channel */
+	chip_num = ch / 4;
+	ch %= 4;
+
+	switch (ctrl) {
+	case V4L2_CID_SHARPNESS:
+		/* Only 286x has sharpness */
+		if (is_tw286x(solo_dev, chip_num)) {
+			rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+						 TW_CHIP_OFFSET_ADDR(chip_num),
+						 TW286x_SHARPNESS(chip_num));
+			*val = rval & 0x0f;
+		} else
+			*val = 0;
+		break;
+	case V4L2_CID_HUE:
+		rval = tw_readbyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
+				   TW_HUE_ADDR(ch));
+		if (is_tw286x(solo_dev, chip_num))
+			*val = (s32)((char)rval) + 128;
+		else
+			*val = rval;
+		break;
+	case V4L2_CID_SATURATION:
+		*val = tw_readbyte(solo_dev, chip_num,
+				   TW286x_SATURATIONU_ADDR(ch),
+				   TW_SATURATION_ADDR(ch));
+		break;
+	case V4L2_CID_CONTRAST:
+		*val = tw_readbyte(solo_dev, chip_num,
+				   TW286x_CONTRAST_ADDR(ch),
+				   TW_CONTRAST_ADDR(ch));
+		break;
+	case V4L2_CID_BRIGHTNESS:
+		rval = tw_readbyte(solo_dev, chip_num,
+				   TW286x_BRIGHTNESS_ADDR(ch),
+				   TW_BRIGHTNESS_ADDR(ch));
+		if (is_tw286x(solo_dev, chip_num))
+			*val = (s32)((char)rval) + 128;
+		else
+			*val = rval;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+#if 0
+/*
+ * For audio output volume, the output channel is only 1. In this case we
+ * don't need to offset TW_CHIP_OFFSET_ADDR. The TW_CHIP_OFFSET_ADDR used
+ * is the base address of the techwell chip.
+ */
+void tw2815_Set_AudioOutVol(struct solo_dev *solo_dev, unsigned int u_val)
+{
+	unsigned int val;
+	unsigned int chip_num;
+
+	chip_num = (solo_dev->nr_chans - 1) / 4;
+
+	val = tw_readbyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
+			  TW_AUDIO_OUTPUT_VOL_ADDR);
+
+	u_val = (val & 0x0f) | (u_val << 4);
+
+	tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
+		     TW_AUDIO_OUTPUT_VOL_ADDR, u_val);
+}
+#endif
+
+u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch)
+{
+	u8 val;
+	u8 chip_num;
+
+	/* Get the right chip and on-chip channel */
+	chip_num = ch / 4;
+	ch %= 4;
+
+	val = tw_readbyte(solo_dev, chip_num,
+			  TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
+			  TW_AUDIO_INPUT_GAIN_ADDR(ch));
+
+	return (ch % 2) ? (val >> 4) : (val & 0x0f);
+}
+
+void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val)
+{
+	u8 old_val;
+	u8 chip_num;
+
+	/* Get the right chip and on-chip channel */
+	chip_num = ch / 4;
+	ch %= 4;
+
+	old_val = tw_readbyte(solo_dev, chip_num,
+			      TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
+			      TW_AUDIO_INPUT_GAIN_ADDR(ch));
+
+	val = (old_val & ((ch % 2) ? 0x0f : 0xf0)) |
+		((ch % 2) ? (val << 4) : val);
+
+	tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
+		     TW_AUDIO_INPUT_GAIN_ADDR(ch), val);
+}
diff --git a/drivers/media/pci/solo6x10/solo6x10-tw28.h b/drivers/media/pci/solo6x10/solo6x10-tw28.h
new file mode 100644
index 0000000000000..0966b45057a33
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10-tw28.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+#ifndef __SOLO6X10_TW28_H
+#define __SOLO6X10_TW28_H
+
+#include "solo6x10.h"
+
+#define TW_NUM_CHIP				4
+#define TW_BASE_ADDR				0x28
+#define TW_CHIP_OFFSET_ADDR(n)			(TW_BASE_ADDR + (n))
+
+/* tw2815 */
+#define TW_AV_STAT_ADDR				0x5a
+#define TW_HUE_ADDR(n)				(0x07 | ((n) << 4))
+#define TW_SATURATION_ADDR(n)			(0x08 | ((n) << 4))
+#define TW_CONTRAST_ADDR(n)			(0x09 | ((n) << 4))
+#define TW_BRIGHTNESS_ADDR(n)			(0x0a | ((n) << 4))
+#define TW_AUDIO_OUTPUT_VOL_ADDR		0x70
+#define TW_AUDIO_INPUT_GAIN_ADDR(n)		(0x60 + ((n > 1) ? 1 : 0))
+
+/* tw286x */
+#define TW286x_AV_STAT_ADDR			0xfd
+#define TW286x_HUE_ADDR(n)			(0x06 | ((n) << 4))
+#define TW286x_SATURATIONU_ADDR(n)		(0x04 | ((n) << 4))
+#define TW286x_SATURATIONV_ADDR(n)		(0x05 | ((n) << 4))
+#define TW286x_CONTRAST_ADDR(n)			(0x02 | ((n) << 4))
+#define TW286x_BRIGHTNESS_ADDR(n)		(0x01 | ((n) << 4))
+#define TW286x_SHARPNESS(n)			(0x03 | ((n) << 4))
+#define TW286x_AUDIO_OUTPUT_VOL_ADDR		0xdf
+#define TW286x_AUDIO_INPUT_GAIN_ADDR(n)		(0xD0 + ((n > 1) ? 1 : 0))
+
+int solo_tw28_init(struct solo_dev *solo_dev);
+
+int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val);
+int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 *val);
+bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch);
+
+u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch);
+void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val);
+int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch);
+
+#if 0
+unsigned int tw2815_get_audio_status(struct SOLO *solo);
+void tw2815_Set_AudioOutVol(struct SOLO *solo, unsigned int u_val);
+#endif
+
+#endif /* __SOLO6X10_TW28_H */
diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
new file mode 100644
index 0000000000000..2e07b497a37c5
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
@@ -0,0 +1,1434 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "solo6x10.h"
+#include "solo6x10-tw28.h"
+#include "solo6x10-jpeg.h"
+
+#define MIN_VID_BUFFERS		2
+#define FRAME_BUF_SIZE		(196 * 1024)
+#define MP4_QS			16
+#define DMA_ALIGN		4096
+
+/* 6010 M4V */
+static unsigned char vop_6010_ntsc_d1[] = {
+	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
+	0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40,
+	0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
+	0x1f, 0x4c, 0x58, 0x10, 0xf0, 0x71, 0x18, 0x3f,
+};
+
+static unsigned char vop_6010_ntsc_cif[] = {
+	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
+	0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40,
+	0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
+	0x1f, 0x4c, 0x2c, 0x10, 0x78, 0x51, 0x18, 0x3f,
+};
+
+static unsigned char vop_6010_pal_d1[] = {
+	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
+	0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40,
+	0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
+	0x1f, 0x4c, 0x58, 0x11, 0x20, 0x71, 0x18, 0x3f,
+};
+
+static unsigned char vop_6010_pal_cif[] = {
+	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
+	0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40,
+	0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
+	0x1f, 0x4c, 0x2c, 0x10, 0x90, 0x51, 0x18, 0x3f,
+};
+
+/* 6110 h.264 */
+static unsigned char vop_6110_ntsc_d1[] = {
+	0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
+	0x9a, 0x74, 0x05, 0x81, 0xec, 0x80, 0x00, 0x00,
+	0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00,
+};
+
+static unsigned char vop_6110_ntsc_cif[] = {
+	0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
+	0x9a, 0x74, 0x0b, 0x0f, 0xc8, 0x00, 0x00, 0x00,
+	0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00,
+};
+
+static unsigned char vop_6110_pal_d1[] = {
+	0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
+	0x9a, 0x74, 0x05, 0x80, 0x93, 0x20, 0x00, 0x00,
+	0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00,
+};
+
+static unsigned char vop_6110_pal_cif[] = {
+	0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
+	0x9a, 0x74, 0x0b, 0x04, 0xb2, 0x00, 0x00, 0x00,
+	0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00,
+};
+
+typedef __le32 vop_header[16];
+
+struct solo_enc_buf {
+	enum solo_enc_types	type;
+	const vop_header	*vh;
+	int			motion;
+};
+
+static int solo_is_motion_on(struct solo_enc_dev *solo_enc)
+{
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+	return (solo_dev->motion_mask >> solo_enc->ch) & 1;
+}
+
+static int solo_motion_detected(struct solo_enc_dev *solo_enc)
+{
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+	unsigned long flags;
+	u32 ch_mask = 1 << solo_enc->ch;
+	int ret = 0;
+
+	spin_lock_irqsave(&solo_enc->motion_lock, flags);
+	if (solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS) & ch_mask) {
+		solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, ch_mask);
+		ret = 1;
+	}
+	spin_unlock_irqrestore(&solo_enc->motion_lock, flags);
+
+	return ret;
+}
+
+static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on)
+{
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+	u32 mask = 1 << solo_enc->ch;
+	unsigned long flags;
+
+	spin_lock_irqsave(&solo_enc->motion_lock, flags);
+
+	if (on)
+		solo_dev->motion_mask |= mask;
+	else
+		solo_dev->motion_mask &= ~mask;
+
+	solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, mask);
+
+	solo_reg_write(solo_dev, SOLO_VI_MOT_ADR,
+		       SOLO_VI_MOTION_EN(solo_dev->motion_mask) |
+		       (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
+
+	spin_unlock_irqrestore(&solo_enc->motion_lock, flags);
+}
+
+void solo_update_mode(struct solo_enc_dev *solo_enc)
+{
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+	int vop_len;
+	unsigned char *vop;
+
+	solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0;
+	solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1);
+
+	if (solo_enc->mode == SOLO_ENC_MODE_CIF) {
+		solo_enc->width = solo_dev->video_hsize >> 1;
+		solo_enc->height = solo_dev->video_vsize;
+		if (solo_dev->type == SOLO_DEV_6110) {
+			if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
+				vop = vop_6110_ntsc_cif;
+				vop_len = sizeof(vop_6110_ntsc_cif);
+			} else {
+				vop = vop_6110_pal_cif;
+				vop_len = sizeof(vop_6110_pal_cif);
+			}
+		} else {
+			if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
+				vop = vop_6010_ntsc_cif;
+				vop_len = sizeof(vop_6010_ntsc_cif);
+			} else {
+				vop = vop_6010_pal_cif;
+				vop_len = sizeof(vop_6010_pal_cif);
+			}
+		}
+	} else {
+		solo_enc->width = solo_dev->video_hsize;
+		solo_enc->height = solo_dev->video_vsize << 1;
+		solo_enc->bw_weight <<= 2;
+		if (solo_dev->type == SOLO_DEV_6110) {
+			if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
+				vop = vop_6110_ntsc_d1;
+				vop_len = sizeof(vop_6110_ntsc_d1);
+			} else {
+				vop = vop_6110_pal_d1;
+				vop_len = sizeof(vop_6110_pal_d1);
+			}
+		} else {
+			if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
+				vop = vop_6010_ntsc_d1;
+				vop_len = sizeof(vop_6010_ntsc_d1);
+			} else {
+				vop = vop_6010_pal_d1;
+				vop_len = sizeof(vop_6010_pal_d1);
+			}
+		}
+	}
+
+	memcpy(solo_enc->vop, vop, vop_len);
+
+	/* Some fixups for 6010/M4V */
+	if (solo_dev->type == SOLO_DEV_6010) {
+		u16 fps = solo_dev->fps * 1000;
+		u16 interval = solo_enc->interval * 1000;
+
+		vop = solo_enc->vop;
+
+		/* Frame rate and interval */
+		vop[22] = fps >> 4;
+		vop[23] = ((fps << 4) & 0xf0) | 0x0c
+			| ((interval >> 13) & 0x3);
+		vop[24] = (interval >> 5) & 0xff;
+		vop[25] = ((interval << 3) & 0xf8) | 0x04;
+	}
+
+	solo_enc->vop_len = vop_len;
+
+	/* Now handle the jpeg header */
+	vop = solo_enc->jpeg_header;
+	vop[SOF0_START + 5] = 0xff & (solo_enc->height >> 8);
+	vop[SOF0_START + 6] = 0xff & solo_enc->height;
+	vop[SOF0_START + 7] = 0xff & (solo_enc->width >> 8);
+	vop[SOF0_START + 8] = 0xff & solo_enc->width;
+
+	memcpy(vop + DQT_START,
+	       jpeg_dqt[solo_g_jpeg_qp(solo_dev, solo_enc->ch)], DQT_LEN);
+}
+
+static int solo_enc_on(struct solo_enc_dev *solo_enc)
+{
+	u8 ch = solo_enc->ch;
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+	u8 interval;
+
+	solo_update_mode(solo_enc);
+
+	/* Make sure to do a bandwidth check */
+	if (solo_enc->bw_weight > solo_dev->enc_bw_remain)
+		return -EBUSY;
+	solo_enc->sequence = 0;
+	solo_enc->motion_last_state = false;
+	solo_enc->frames_since_last_motion = 0;
+	solo_dev->enc_bw_remain -= solo_enc->bw_weight;
+
+	if (solo_enc->type == SOLO_ENC_TYPE_EXT)
+		solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1);
+
+	/* Disable all encoding for this channel */
+	solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0);
+
+	/* Common for both std and ext encoding */
+	solo_reg_write(solo_dev, SOLO_VE_CH_INTL(ch),
+		       solo_enc->interlaced ? 1 : 0);
+
+	if (solo_enc->interlaced)
+		interval = solo_enc->interval - 1;
+	else
+		interval = solo_enc->interval;
+
+	/* Standard encoding only */
+	solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), solo_enc->gop);
+	solo_reg_write(solo_dev, SOLO_VE_CH_QP(ch), solo_enc->qp);
+	solo_reg_write(solo_dev, SOLO_CAP_CH_INTV(ch), interval);
+
+	/* Extended encoding only */
+	solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(ch), solo_enc->gop);
+	solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(ch), solo_enc->qp);
+	solo_reg_write(solo_dev, SOLO_CAP_CH_INTV_E(ch), interval);
+
+	/* Enables the standard encoder */
+	solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode);
+
+	return 0;
+}
+
+static void solo_enc_off(struct solo_enc_dev *solo_enc)
+{
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+	solo_dev->enc_bw_remain += solo_enc->bw_weight;
+
+	solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0);
+	solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0);
+}
+
+static int enc_get_mpeg_dma(struct solo_dev *solo_dev, dma_addr_t dma,
+			      unsigned int off, unsigned int size)
+{
+	int ret;
+
+	if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
+		return -EINVAL;
+
+	/* Single shot */
+	if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) {
+		return solo_p2m_dma_t(solo_dev, 0, dma,
+				      SOLO_MP4E_EXT_ADDR(solo_dev) + off, size,
+				      0, 0);
+	}
+
+	/* Buffer wrap */
+	ret = solo_p2m_dma_t(solo_dev, 0, dma,
+			     SOLO_MP4E_EXT_ADDR(solo_dev) + off,
+			     SOLO_MP4E_EXT_SIZE(solo_dev) - off, 0, 0);
+
+	if (!ret) {
+		ret = solo_p2m_dma_t(solo_dev, 0,
+			     dma + SOLO_MP4E_EXT_SIZE(solo_dev) - off,
+			     SOLO_MP4E_EXT_ADDR(solo_dev),
+			     size + off - SOLO_MP4E_EXT_SIZE(solo_dev), 0, 0);
+	}
+
+	return ret;
+}
+
+/* Build a descriptor queue out of an SG list and send it to the P2M for
+ * processing. */
+static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip,
+			  struct sg_table *vbuf, int off, int size,
+			  unsigned int base, unsigned int base_size)
+{
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+	struct scatterlist *sg;
+	int i;
+	int ret;
+
+	if (WARN_ON_ONCE(size > FRAME_BUF_SIZE))
+		return -EINVAL;
+
+	solo_enc->desc_count = 1;
+
+	for_each_sg(vbuf->sgl, sg, vbuf->nents, i) {
+		struct solo_p2m_desc *desc;
+		dma_addr_t dma;
+		int len;
+		int left = base_size - off;
+
+		desc = &solo_enc->desc_items[solo_enc->desc_count++];
+		dma = sg_dma_address(sg);
+		len = sg_dma_len(sg);
+
+		/* We assume this is smaller than the scatter size */
+		BUG_ON(skip >= len);
+		if (skip) {
+			len -= skip;
+			dma += skip;
+			size -= skip;
+			skip = 0;
+		}
+
+		len = min(len, size);
+
+		if (len <= left) {
+			/* Single descriptor */
+			solo_p2m_fill_desc(desc, 0, dma, base + off,
+					   len, 0, 0);
+		} else {
+			/* Buffer wrap */
+			/* XXX: Do these as separate DMA requests, to avoid
+			   timeout errors triggered by awkwardly sized
+			   descriptors. See
+			   <https://github.com/bluecherrydvr/solo6x10/issues/8>
+			 */
+			ret = solo_p2m_dma_t(solo_dev, 0, dma, base + off,
+					     left, 0, 0);
+			if (ret)
+				return ret;
+
+			ret = solo_p2m_dma_t(solo_dev, 0, dma + left, base,
+					     len - left, 0, 0);
+			if (ret)
+				return ret;
+
+			solo_enc->desc_count--;
+		}
+
+		size -= len;
+		if (size <= 0)
+			break;
+
+		off += len;
+		if (off >= base_size)
+			off -= base_size;
+
+		/* Because we may use two descriptors per loop */
+		if (solo_enc->desc_count >= (solo_enc->desc_nelts - 1)) {
+			ret = solo_p2m_dma_desc(solo_dev, solo_enc->desc_items,
+						solo_enc->desc_dma,
+						solo_enc->desc_count - 1);
+			if (ret)
+				return ret;
+			solo_enc->desc_count = 1;
+		}
+	}
+
+	if (solo_enc->desc_count <= 1)
+		return 0;
+
+	return solo_p2m_dma_desc(solo_dev, solo_enc->desc_items,
+			solo_enc->desc_dma, solo_enc->desc_count - 1);
+}
+
+/* Extract values from VOP header - VE_STATUSxx */
+static inline int vop_interlaced(const vop_header *vh)
+{
+	return (__le32_to_cpu((*vh)[0]) >> 30) & 1;
+}
+
+static inline u8 vop_channel(const vop_header *vh)
+{
+	return (__le32_to_cpu((*vh)[0]) >> 24) & 0x1F;
+}
+
+static inline u8 vop_type(const vop_header *vh)
+{
+	return (__le32_to_cpu((*vh)[0]) >> 22) & 3;
+}
+
+static inline u32 vop_mpeg_size(const vop_header *vh)
+{
+	return __le32_to_cpu((*vh)[0]) & 0xFFFFF;
+}
+
+static inline u8 vop_hsize(const vop_header *vh)
+{
+	return (__le32_to_cpu((*vh)[1]) >> 8) & 0xFF;
+}
+
+static inline u8 vop_vsize(const vop_header *vh)
+{
+	return __le32_to_cpu((*vh)[1]) & 0xFF;
+}
+
+static inline u32 vop_mpeg_offset(const vop_header *vh)
+{
+	return __le32_to_cpu((*vh)[2]);
+}
+
+static inline u32 vop_jpeg_offset(const vop_header *vh)
+{
+	return __le32_to_cpu((*vh)[3]);
+}
+
+static inline u32 vop_jpeg_size(const vop_header *vh)
+{
+	return __le32_to_cpu((*vh)[4]) & 0xFFFFF;
+}
+
+static inline u32 vop_sec(const vop_header *vh)
+{
+	return __le32_to_cpu((*vh)[5]);
+}
+
+static inline u32 vop_usec(const vop_header *vh)
+{
+	return __le32_to_cpu((*vh)[6]);
+}
+
+static int solo_fill_jpeg(struct solo_enc_dev *solo_enc,
+			  struct vb2_buffer *vb, const vop_header *vh)
+{
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+	struct sg_table *vbuf = vb2_dma_sg_plane_desc(vb, 0);
+	int frame_size;
+	int ret;
+
+	vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+
+	if (vb2_plane_size(vb, 0) < vop_jpeg_size(vh) + solo_enc->jpeg_len)
+		return -EIO;
+
+	frame_size = ALIGN(vop_jpeg_size(vh) + solo_enc->jpeg_len, DMA_ALIGN);
+	vb2_set_plane_payload(vb, 0, vop_jpeg_size(vh) + solo_enc->jpeg_len);
+
+	/* may discard all previous data in vbuf->sgl */
+	if (!dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
+			DMA_FROM_DEVICE))
+		return -ENOMEM;
+	ret = solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf,
+			     vop_jpeg_offset(vh) - SOLO_JPEG_EXT_ADDR(solo_dev),
+			     frame_size, SOLO_JPEG_EXT_ADDR(solo_dev),
+			     SOLO_JPEG_EXT_SIZE(solo_dev));
+	dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
+			DMA_FROM_DEVICE);
+
+	/* add the header only after dma_unmap_sg() */
+	sg_copy_from_buffer(vbuf->sgl, vbuf->nents,
+			    solo_enc->jpeg_header, solo_enc->jpeg_len);
+
+	return ret;
+}
+
+static int solo_fill_mpeg(struct solo_enc_dev *solo_enc,
+		struct vb2_buffer *vb, const vop_header *vh)
+{
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+	struct sg_table *vbuf = vb2_dma_sg_plane_desc(vb, 0);
+	int frame_off, frame_size;
+	int skip = 0;
+	int ret;
+
+	if (vb2_plane_size(vb, 0) < vop_mpeg_size(vh))
+		return -EIO;
+
+	/* If this is a key frame, add extra header */
+	vb->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME |
+		V4L2_BUF_FLAG_BFRAME);
+	if (!vop_type(vh)) {
+		skip = solo_enc->vop_len;
+		vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+		vb2_set_plane_payload(vb, 0, vop_mpeg_size(vh) +
+			solo_enc->vop_len);
+	} else {
+		vb->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+		vb2_set_plane_payload(vb, 0, vop_mpeg_size(vh));
+	}
+
+	/* Now get the actual mpeg payload */
+	frame_off = (vop_mpeg_offset(vh) - SOLO_MP4E_EXT_ADDR(solo_dev) +
+		sizeof(*vh)) % SOLO_MP4E_EXT_SIZE(solo_dev);
+	frame_size = ALIGN(vop_mpeg_size(vh) + skip, DMA_ALIGN);
+
+	/* may discard all previous data in vbuf->sgl */
+	if (!dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
+			DMA_FROM_DEVICE))
+		return -ENOMEM;
+	ret = solo_send_desc(solo_enc, skip, vbuf, frame_off, frame_size,
+			SOLO_MP4E_EXT_ADDR(solo_dev),
+			SOLO_MP4E_EXT_SIZE(solo_dev));
+	dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
+			DMA_FROM_DEVICE);
+
+	/* add the header only after dma_unmap_sg() */
+	if (!vop_type(vh))
+		sg_copy_from_buffer(vbuf->sgl, vbuf->nents,
+				    solo_enc->vop, solo_enc->vop_len);
+	return ret;
+}
+
+static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
+			    struct vb2_buffer *vb, struct solo_enc_buf *enc_buf)
+{
+	const vop_header *vh = enc_buf->vh;
+	int ret;
+
+	switch (solo_enc->fmt) {
+	case V4L2_PIX_FMT_MPEG4:
+	case V4L2_PIX_FMT_H264:
+		ret = solo_fill_mpeg(solo_enc, vb, vh);
+		break;
+	default: /* V4L2_PIX_FMT_MJPEG */
+		ret = solo_fill_jpeg(solo_enc, vb, vh);
+		break;
+	}
+
+	if (!ret) {
+		bool send_event = false;
+
+		vb->v4l2_buf.sequence = solo_enc->sequence++;
+		vb->v4l2_buf.timestamp.tv_sec = vop_sec(vh);
+		vb->v4l2_buf.timestamp.tv_usec = vop_usec(vh);
+
+		/* Check for motion flags */
+		if (solo_is_motion_on(solo_enc)) {
+			/* It takes a few frames for the hardware to detect
+			 * motion. Once it does it clears the motion detection
+			 * register and it takes again a few frames before
+			 * motion is seen. This means in practice that when the
+			 * motion field is 1, it will go back to 0 for the next
+			 * frame. This leads to motion detection event being
+			 * sent all the time, which is not what we want.
+			 * Instead wait a few frames before deciding that the
+			 * motion has halted. After some experimentation it
+			 * turns out that waiting for 5 frames works well.
+			 */
+			if (enc_buf->motion == 0 &&
+			    solo_enc->motion_last_state &&
+			    solo_enc->frames_since_last_motion++ > 5)
+				send_event = true;
+			else if (enc_buf->motion) {
+				solo_enc->frames_since_last_motion = 0;
+				send_event = !solo_enc->motion_last_state;
+			}
+		}
+
+		if (send_event) {
+			struct v4l2_event ev = {
+				.type = V4L2_EVENT_MOTION_DET,
+				.u.motion_det = {
+					.flags = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ,
+					.frame_sequence = vb->v4l2_buf.sequence,
+					.region_mask = enc_buf->motion ? 1 : 0,
+				},
+			};
+
+			solo_enc->motion_last_state = enc_buf->motion;
+			solo_enc->frames_since_last_motion = 0;
+			v4l2_event_queue(solo_enc->vfd, &ev);
+		}
+	}
+
+	vb2_buffer_done(vb, ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+
+	return ret;
+}
+
+static void solo_enc_handle_one(struct solo_enc_dev *solo_enc,
+				struct solo_enc_buf *enc_buf)
+{
+	struct solo_vb2_buf *vb;
+	unsigned long flags;
+
+	mutex_lock(&solo_enc->lock);
+	if (solo_enc->type != enc_buf->type)
+		goto unlock;
+
+	spin_lock_irqsave(&solo_enc->av_lock, flags);
+	if (list_empty(&solo_enc->vidq_active)) {
+		spin_unlock_irqrestore(&solo_enc->av_lock, flags);
+		goto unlock;
+	}
+	vb = list_first_entry(&solo_enc->vidq_active, struct solo_vb2_buf,
+		list);
+	list_del(&vb->list);
+	spin_unlock_irqrestore(&solo_enc->av_lock, flags);
+
+	solo_enc_fillbuf(solo_enc, &vb->vb, enc_buf);
+unlock:
+	mutex_unlock(&solo_enc->lock);
+}
+
+void solo_enc_v4l2_isr(struct solo_dev *solo_dev)
+{
+	wake_up_interruptible_all(&solo_dev->ring_thread_wait);
+}
+
+static void solo_handle_ring(struct solo_dev *solo_dev)
+{
+	for (;;) {
+		struct solo_enc_dev *solo_enc;
+		struct solo_enc_buf enc_buf;
+		u32 mpeg_current, off;
+		u8 ch;
+		u8 cur_q;
+
+		/* Check if the hardware has any new ones in the queue */
+		cur_q = solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xff;
+		if (cur_q == solo_dev->enc_idx)
+			break;
+
+		mpeg_current = solo_reg_read(solo_dev,
+					SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
+		solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS;
+
+		ch = (mpeg_current >> 24) & 0x1f;
+		off = mpeg_current & 0x00ffffff;
+
+		if (ch >= SOLO_MAX_CHANNELS) {
+			ch -= SOLO_MAX_CHANNELS;
+			enc_buf.type = SOLO_ENC_TYPE_EXT;
+		} else
+			enc_buf.type = SOLO_ENC_TYPE_STD;
+
+		solo_enc = solo_dev->v4l2_enc[ch];
+		if (solo_enc == NULL) {
+			dev_err(&solo_dev->pdev->dev,
+				"Got spurious packet for channel %d\n", ch);
+			continue;
+		}
+
+		/* FAIL... */
+		if (enc_get_mpeg_dma(solo_dev, solo_dev->vh_dma, off,
+				     sizeof(vop_header)))
+			continue;
+
+		enc_buf.vh = solo_dev->vh_buf;
+
+		/* Sanity check */
+		if (vop_mpeg_offset(enc_buf.vh) !=
+			SOLO_MP4E_EXT_ADDR(solo_dev) + off)
+			continue;
+
+		if (solo_motion_detected(solo_enc))
+			enc_buf.motion = 1;
+		else
+			enc_buf.motion = 0;
+
+		solo_enc_handle_one(solo_enc, &enc_buf);
+	}
+}
+
+static int solo_ring_thread(void *data)
+{
+	struct solo_dev *solo_dev = data;
+	DECLARE_WAITQUEUE(wait, current);
+
+	set_freezable();
+	add_wait_queue(&solo_dev->ring_thread_wait, &wait);
+
+	for (;;) {
+		long timeout = schedule_timeout_interruptible(HZ);
+
+		if (timeout == -ERESTARTSYS || kthread_should_stop())
+			break;
+		solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
+		solo_handle_ring(solo_dev);
+		solo_irq_on(solo_dev, SOLO_IRQ_ENCODER);
+		try_to_freeze();
+	}
+
+	remove_wait_queue(&solo_dev->ring_thread_wait, &wait);
+
+	return 0;
+}
+
+static int solo_enc_queue_setup(struct vb2_queue *q,
+				const struct v4l2_format *fmt,
+				unsigned int *num_buffers,
+				unsigned int *num_planes, unsigned int sizes[],
+				void *alloc_ctxs[])
+{
+	sizes[0] = FRAME_BUF_SIZE;
+	*num_planes = 1;
+
+	if (*num_buffers < MIN_VID_BUFFERS)
+		*num_buffers = MIN_VID_BUFFERS;
+
+	return 0;
+}
+
+static void solo_enc_buf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vq);
+	struct solo_vb2_buf *solo_vb =
+		container_of(vb, struct solo_vb2_buf, vb);
+
+	spin_lock(&solo_enc->av_lock);
+	list_add_tail(&solo_vb->list, &solo_enc->vidq_active);
+	spin_unlock(&solo_enc->av_lock);
+}
+
+static int solo_ring_start(struct solo_dev *solo_dev)
+{
+	solo_dev->ring_thread = kthread_run(solo_ring_thread, solo_dev,
+					    SOLO6X10_NAME "_ring");
+	if (IS_ERR(solo_dev->ring_thread)) {
+		int err = PTR_ERR(solo_dev->ring_thread);
+
+		solo_dev->ring_thread = NULL;
+		return err;
+	}
+
+	solo_irq_on(solo_dev, SOLO_IRQ_ENCODER);
+
+	return 0;
+}
+
+static void solo_ring_stop(struct solo_dev *solo_dev)
+{
+	if (solo_dev->ring_thread) {
+		kthread_stop(solo_dev->ring_thread);
+		solo_dev->ring_thread = NULL;
+	}
+
+	solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
+}
+
+static int solo_enc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
+	int ret;
+
+	ret = solo_enc_on(solo_enc);
+	if (ret)
+		return ret;
+	return solo_ring_start(solo_enc->solo_dev);
+}
+
+static void solo_enc_stop_streaming(struct vb2_queue *q)
+{
+	struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
+
+	solo_enc_off(solo_enc);
+	INIT_LIST_HEAD(&solo_enc->vidq_active);
+	solo_ring_stop(solo_enc->solo_dev);
+}
+
+static struct vb2_ops solo_enc_video_qops = {
+	.queue_setup	= solo_enc_queue_setup,
+	.buf_queue	= solo_enc_buf_queue,
+	.start_streaming = solo_enc_start_streaming,
+	.stop_streaming = solo_enc_stop_streaming,
+	.wait_prepare	= vb2_ops_wait_prepare,
+	.wait_finish	= vb2_ops_wait_finish,
+};
+
+static int solo_enc_querycap(struct file *file, void  *priv,
+			     struct v4l2_capability *cap)
+{
+	struct solo_enc_dev *solo_enc = video_drvdata(file);
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+	strcpy(cap->driver, SOLO6X10_NAME);
+	snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d",
+		 solo_enc->ch);
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
+		 pci_name(solo_dev->pdev));
+	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
+			V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int solo_enc_enum_input(struct file *file, void *priv,
+			       struct v4l2_input *input)
+{
+	struct solo_enc_dev *solo_enc = video_drvdata(file);
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+	if (input->index)
+		return -EINVAL;
+
+	snprintf(input->name, sizeof(input->name), "Encoder %d",
+		 solo_enc->ch + 1);
+	input->type = V4L2_INPUT_TYPE_CAMERA;
+	input->std = solo_enc->vfd->tvnorms;
+
+	if (!tw28_get_video_status(solo_dev, solo_enc->ch))
+		input->status = V4L2_IN_ST_NO_SIGNAL;
+
+	return 0;
+}
+
+static int solo_enc_set_input(struct file *file, void *priv,
+			      unsigned int index)
+{
+	if (index)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int solo_enc_get_input(struct file *file, void *priv,
+			      unsigned int *index)
+{
+	*index = 0;
+
+	return 0;
+}
+
+static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
+				 struct v4l2_fmtdesc *f)
+{
+	struct solo_enc_dev *solo_enc = video_drvdata(file);
+	int dev_type = solo_enc->solo_dev->type;
+
+	switch (f->index) {
+	case 0:
+		switch (dev_type) {
+		case SOLO_DEV_6010:
+			f->pixelformat = V4L2_PIX_FMT_MPEG4;
+			strcpy(f->description, "MPEG-4 part 2");
+			break;
+		case SOLO_DEV_6110:
+			f->pixelformat = V4L2_PIX_FMT_H264;
+			strcpy(f->description, "H.264");
+			break;
+		}
+		break;
+	case 1:
+		f->pixelformat = V4L2_PIX_FMT_MJPEG;
+		strcpy(f->description, "MJPEG");
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	f->flags = V4L2_FMT_FLAG_COMPRESSED;
+
+	return 0;
+}
+
+static inline int solo_valid_pixfmt(u32 pixfmt, int dev_type)
+{
+	return (pixfmt == V4L2_PIX_FMT_H264 && dev_type == SOLO_DEV_6110)
+		|| (pixfmt == V4L2_PIX_FMT_MPEG4 && dev_type == SOLO_DEV_6010)
+		|| pixfmt == V4L2_PIX_FMT_MJPEG ? 0 : -EINVAL;
+}
+
+static int solo_enc_try_fmt_cap(struct file *file, void *priv,
+			    struct v4l2_format *f)
+{
+	struct solo_enc_dev *solo_enc = video_drvdata(file);
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+
+	if (solo_valid_pixfmt(pix->pixelformat, solo_dev->type))
+		return -EINVAL;
+
+	if (pix->width < solo_dev->video_hsize ||
+	    pix->height < solo_dev->video_vsize << 1) {
+		/* Default to CIF 1/2 size */
+		pix->width = solo_dev->video_hsize >> 1;
+		pix->height = solo_dev->video_vsize;
+	} else {
+		/* Full frame */
+		pix->width = solo_dev->video_hsize;
+		pix->height = solo_dev->video_vsize << 1;
+	}
+
+	switch (pix->field) {
+	case V4L2_FIELD_NONE:
+	case V4L2_FIELD_INTERLACED:
+		break;
+	case V4L2_FIELD_ANY:
+	default:
+		pix->field = V4L2_FIELD_INTERLACED;
+		break;
+	}
+
+	/* Just set these */
+	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	pix->sizeimage = FRAME_BUF_SIZE;
+	pix->bytesperline = 0;
+	pix->priv = 0;
+
+	return 0;
+}
+
+static int solo_enc_set_fmt_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct solo_enc_dev *solo_enc = video_drvdata(file);
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	int ret;
+
+	if (vb2_is_busy(&solo_enc->vidq))
+		return -EBUSY;
+
+	ret = solo_enc_try_fmt_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	if (pix->width == solo_dev->video_hsize)
+		solo_enc->mode = SOLO_ENC_MODE_D1;
+	else
+		solo_enc->mode = SOLO_ENC_MODE_CIF;
+
+	/* This does not change the encoder at all */
+	solo_enc->fmt = pix->pixelformat;
+
+	/*
+	 * More information is needed about these 'extended' types. As far
+	 * as I can tell these are basically additional video streams with
+	 * different MPEG encoding attributes that can run in parallel with
+	 * the main stream. If so, then this should be implemented as a
+	 * second video node. Abusing priv like this is certainly not the
+	 * right approach.
+	if (pix->priv)
+		solo_enc->type = SOLO_ENC_TYPE_EXT;
+	 */
+	solo_update_mode(solo_enc);
+	return 0;
+}
+
+static int solo_enc_get_fmt_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct solo_enc_dev *solo_enc = video_drvdata(file);
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+
+	pix->width = solo_enc->width;
+	pix->height = solo_enc->height;
+	pix->pixelformat = solo_enc->fmt;
+	pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
+		     V4L2_FIELD_NONE;
+	pix->sizeimage = FRAME_BUF_SIZE;
+	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	pix->priv = 0;
+
+	return 0;
+}
+
+static int solo_enc_g_std(struct file *file, void *priv, v4l2_std_id *i)
+{
+	struct solo_enc_dev *solo_enc = video_drvdata(file);
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+	if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
+		*i = V4L2_STD_NTSC_M;
+	else
+		*i = V4L2_STD_PAL;
+	return 0;
+}
+
+static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id std)
+{
+	struct solo_enc_dev *solo_enc = video_drvdata(file);
+
+	return solo_set_video_type(solo_enc->solo_dev, std & V4L2_STD_625_50);
+}
+
+static int solo_enum_framesizes(struct file *file, void *priv,
+				struct v4l2_frmsizeenum *fsize)
+{
+	struct solo_enc_dev *solo_enc = video_drvdata(file);
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+	if (solo_valid_pixfmt(fsize->pixel_format, solo_dev->type))
+		return -EINVAL;
+
+	switch (fsize->index) {
+	case 0:
+		fsize->discrete.width = solo_dev->video_hsize >> 1;
+		fsize->discrete.height = solo_dev->video_vsize;
+		break;
+	case 1:
+		fsize->discrete.width = solo_dev->video_hsize;
+		fsize->discrete.height = solo_dev->video_vsize << 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+
+	return 0;
+}
+
+static int solo_enum_frameintervals(struct file *file, void *priv,
+				    struct v4l2_frmivalenum *fintv)
+{
+	struct solo_enc_dev *solo_enc = video_drvdata(file);
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+	if (solo_valid_pixfmt(fintv->pixel_format, solo_dev->type))
+		return -EINVAL;
+	if (fintv->index)
+		return -EINVAL;
+	if ((fintv->width != solo_dev->video_hsize >> 1 ||
+	     fintv->height != solo_dev->video_vsize) &&
+	    (fintv->width != solo_dev->video_hsize ||
+	     fintv->height != solo_dev->video_vsize << 1))
+		return -EINVAL;
+
+	fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
+
+	fintv->stepwise.min.numerator = 1;
+	fintv->stepwise.min.denominator = solo_dev->fps;
+
+	fintv->stepwise.max.numerator = 15;
+	fintv->stepwise.max.denominator = solo_dev->fps;
+
+	fintv->stepwise.step.numerator = 1;
+	fintv->stepwise.step.denominator = solo_dev->fps;
+
+	return 0;
+}
+
+static int solo_g_parm(struct file *file, void *priv,
+		       struct v4l2_streamparm *sp)
+{
+	struct solo_enc_dev *solo_enc = video_drvdata(file);
+	struct v4l2_captureparm *cp = &sp->parm.capture;
+
+	cp->capability = V4L2_CAP_TIMEPERFRAME;
+	cp->timeperframe.numerator = solo_enc->interval;
+	cp->timeperframe.denominator = solo_enc->solo_dev->fps;
+	cp->capturemode = 0;
+	/* XXX: Shouldn't we be able to get/set this from videobuf? */
+	cp->readbuffers = 2;
+
+	return 0;
+}
+
+static inline int calc_interval(u8 fps, u32 n, u32 d)
+{
+	if (!n || !d)
+		return 1;
+	if (d == fps)
+		return n;
+	n *= fps;
+	return min(15U, n / d + (n % d >= (fps >> 1)));
+}
+
+static int solo_s_parm(struct file *file, void *priv,
+		       struct v4l2_streamparm *sp)
+{
+	struct solo_enc_dev *solo_enc = video_drvdata(file);
+	struct v4l2_fract *t = &sp->parm.capture.timeperframe;
+	u8 fps = solo_enc->solo_dev->fps;
+
+	if (vb2_is_streaming(&solo_enc->vidq))
+		return -EBUSY;
+
+	solo_enc->interval = calc_interval(fps, t->numerator, t->denominator);
+	solo_update_mode(solo_enc);
+	return solo_g_parm(file, priv, sp);
+}
+
+static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct solo_enc_dev *solo_enc =
+		container_of(ctrl->handler, struct solo_enc_dev, hdl);
+	struct solo_dev *solo_dev = solo_enc->solo_dev;
+	int err;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+	case V4L2_CID_CONTRAST:
+	case V4L2_CID_SATURATION:
+	case V4L2_CID_HUE:
+	case V4L2_CID_SHARPNESS:
+		return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
+					 ctrl->val);
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		solo_enc->gop = ctrl->val;
+		solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch), solo_enc->gop);
+		solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch), solo_enc->gop);
+		return 0;
+	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+		solo_enc->qp = ctrl->val;
+		solo_reg_write(solo_dev, SOLO_VE_CH_QP(solo_enc->ch), solo_enc->qp);
+		solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(solo_enc->ch), solo_enc->qp);
+		return 0;
+	case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD:
+		solo_enc->motion_thresh = ctrl->val << 8;
+		if (!solo_enc->motion_global || !solo_enc->motion_enabled)
+			return 0;
+		return solo_set_motion_threshold(solo_dev, solo_enc->ch,
+				solo_enc->motion_thresh);
+	case V4L2_CID_DETECT_MD_MODE:
+		solo_enc->motion_global = ctrl->val == V4L2_DETECT_MD_MODE_GLOBAL;
+		solo_enc->motion_enabled = ctrl->val > V4L2_DETECT_MD_MODE_DISABLED;
+		if (ctrl->val) {
+			if (solo_enc->motion_global)
+				solo_set_motion_threshold(solo_dev, solo_enc->ch,
+					solo_enc->motion_thresh);
+			else
+				solo_set_motion_block(solo_dev, solo_enc->ch,
+					solo_enc->md_thresholds->p_cur.p_u16);
+		}
+		solo_motion_toggle(solo_enc, ctrl->val);
+		return 0;
+	case V4L2_CID_DETECT_MD_THRESHOLD_GRID:
+		if (solo_enc->motion_enabled && !solo_enc->motion_global)
+			return solo_set_motion_block(solo_dev, solo_enc->ch,
+					solo_enc->md_thresholds->p_new.p_u16);
+		break;
+	case V4L2_CID_OSD_TEXT:
+		strcpy(solo_enc->osd_text, ctrl->p_new.p_char);
+		err = solo_osd_print(solo_enc);
+		return err;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int solo_subscribe_event(struct v4l2_fh *fh,
+				const struct v4l2_event_subscription *sub)
+{
+
+	switch (sub->type) {
+	case V4L2_EVENT_CTRL:
+		return v4l2_ctrl_subscribe_event(fh, sub);
+	case V4L2_EVENT_MOTION_DET:
+		/* Allow for up to 30 events (1 second for NTSC) to be
+		 * stored. */
+		return v4l2_event_subscribe(fh, sub, 30, NULL);
+	}
+	return -EINVAL;
+}
+
+static const struct v4l2_file_operations solo_enc_fops = {
+	.owner			= THIS_MODULE,
+	.open			= v4l2_fh_open,
+	.release		= vb2_fop_release,
+	.read			= vb2_fop_read,
+	.poll			= vb2_fop_poll,
+	.mmap			= vb2_fop_mmap,
+	.unlocked_ioctl		= video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
+	.vidioc_querycap		= solo_enc_querycap,
+	.vidioc_s_std			= solo_enc_s_std,
+	.vidioc_g_std			= solo_enc_g_std,
+	/* Input callbacks */
+	.vidioc_enum_input		= solo_enc_enum_input,
+	.vidioc_s_input			= solo_enc_set_input,
+	.vidioc_g_input			= solo_enc_get_input,
+	/* Video capture format callbacks */
+	.vidioc_enum_fmt_vid_cap	= solo_enc_enum_fmt_cap,
+	.vidioc_try_fmt_vid_cap		= solo_enc_try_fmt_cap,
+	.vidioc_s_fmt_vid_cap		= solo_enc_set_fmt_cap,
+	.vidioc_g_fmt_vid_cap		= solo_enc_get_fmt_cap,
+	/* Streaming I/O */
+	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
+	.vidioc_querybuf		= vb2_ioctl_querybuf,
+	.vidioc_qbuf			= vb2_ioctl_qbuf,
+	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
+	.vidioc_streamon		= vb2_ioctl_streamon,
+	.vidioc_streamoff		= vb2_ioctl_streamoff,
+	/* Frame size and interval */
+	.vidioc_enum_framesizes		= solo_enum_framesizes,
+	.vidioc_enum_frameintervals	= solo_enum_frameintervals,
+	/* Video capture parameters */
+	.vidioc_s_parm			= solo_s_parm,
+	.vidioc_g_parm			= solo_g_parm,
+	/* Logging and events */
+	.vidioc_log_status		= v4l2_ctrl_log_status,
+	.vidioc_subscribe_event		= solo_subscribe_event,
+	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
+};
+
+static const struct video_device solo_enc_template = {
+	.name			= SOLO6X10_NAME,
+	.fops			= &solo_enc_fops,
+	.ioctl_ops		= &solo_enc_ioctl_ops,
+	.minor			= -1,
+	.release		= video_device_release,
+	.tvnorms		= V4L2_STD_NTSC_M | V4L2_STD_PAL,
+};
+
+static const struct v4l2_ctrl_ops solo_ctrl_ops = {
+	.s_ctrl = solo_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config solo_osd_text_ctrl = {
+	.ops = &solo_ctrl_ops,
+	.id = V4L2_CID_OSD_TEXT,
+	.name = "OSD Text",
+	.type = V4L2_CTRL_TYPE_STRING,
+	.max = OSD_TEXT_MAX,
+	.step = 1,
+};
+
+/* Motion Detection Threshold matrix */
+static const struct v4l2_ctrl_config solo_md_thresholds = {
+	.ops = &solo_ctrl_ops,
+	.id = V4L2_CID_DETECT_MD_THRESHOLD_GRID,
+	.dims = { SOLO_MOTION_SZ, SOLO_MOTION_SZ },
+	.def = SOLO_DEF_MOT_THRESH,
+	.max = 65535,
+	.step = 1,
+};
+
+static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
+					   u8 ch, unsigned nr)
+{
+	struct solo_enc_dev *solo_enc;
+	struct v4l2_ctrl_handler *hdl;
+	int ret;
+
+	solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
+	if (!solo_enc)
+		return ERR_PTR(-ENOMEM);
+
+	hdl = &solo_enc->hdl;
+	v4l2_ctrl_handler_init(hdl, 10);
+	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+			V4L2_CID_HUE, 0, 255, 1, 128);
+	if (tw28_has_sharpness(solo_dev, ch))
+		v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+			V4L2_CID_SHARPNESS, 0, 15, 1, 0);
+	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+			V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, solo_dev->fps);
+	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+			V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 31, 1, SOLO_DEFAULT_QP);
+	v4l2_ctrl_new_std_menu(hdl, &solo_ctrl_ops,
+			V4L2_CID_DETECT_MD_MODE,
+			V4L2_DETECT_MD_MODE_THRESHOLD_GRID, 0,
+			V4L2_DETECT_MD_MODE_DISABLED);
+	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+			V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD, 0, 0xff, 1,
+			SOLO_DEF_MOT_THRESH >> 8);
+	v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL);
+	solo_enc->md_thresholds =
+		v4l2_ctrl_new_custom(hdl, &solo_md_thresholds, NULL);
+	if (hdl->error) {
+		ret = hdl->error;
+		goto hdl_free;
+	}
+
+	solo_enc->solo_dev = solo_dev;
+	solo_enc->ch = ch;
+	mutex_init(&solo_enc->lock);
+	spin_lock_init(&solo_enc->av_lock);
+	INIT_LIST_HEAD(&solo_enc->vidq_active);
+	solo_enc->fmt = (solo_dev->type == SOLO_DEV_6010) ?
+		V4L2_PIX_FMT_MPEG4 : V4L2_PIX_FMT_H264;
+	solo_enc->type = SOLO_ENC_TYPE_STD;
+
+	solo_enc->qp = SOLO_DEFAULT_QP;
+	solo_enc->gop = solo_dev->fps;
+	solo_enc->interval = 1;
+	solo_enc->mode = SOLO_ENC_MODE_CIF;
+	solo_enc->motion_global = true;
+	solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
+	solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+	solo_enc->vidq.ops = &solo_enc_video_qops;
+	solo_enc->vidq.mem_ops = &vb2_dma_sg_memops;
+	solo_enc->vidq.drv_priv = solo_enc;
+	solo_enc->vidq.gfp_flags = __GFP_DMA32;
+	solo_enc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	solo_enc->vidq.buf_struct_size = sizeof(struct solo_vb2_buf);
+	solo_enc->vidq.lock = &solo_enc->lock;
+	ret = vb2_queue_init(&solo_enc->vidq);
+	if (ret)
+		goto hdl_free;
+	solo_update_mode(solo_enc);
+
+	spin_lock_init(&solo_enc->motion_lock);
+
+	/* Initialize this per encoder */
+	solo_enc->jpeg_len = sizeof(jpeg_header);
+	memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len);
+
+	solo_enc->desc_nelts = 32;
+	solo_enc->desc_items = pci_alloc_consistent(solo_dev->pdev,
+				      sizeof(struct solo_p2m_desc) *
+				      solo_enc->desc_nelts,
+				      &solo_enc->desc_dma);
+	ret = -ENOMEM;
+	if (solo_enc->desc_items == NULL)
+		goto hdl_free;
+
+	solo_enc->vfd = video_device_alloc();
+	if (!solo_enc->vfd)
+		goto pci_free;
+
+	*solo_enc->vfd = solo_enc_template;
+	solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev;
+	solo_enc->vfd->ctrl_handler = hdl;
+	solo_enc->vfd->queue = &solo_enc->vidq;
+	solo_enc->vfd->lock = &solo_enc->lock;
+	video_set_drvdata(solo_enc->vfd, solo_enc);
+	ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr);
+	if (ret < 0)
+		goto vdev_release;
+
+	snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
+		 "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num,
+		 solo_enc->vfd->num);
+
+	return solo_enc;
+
+vdev_release:
+	video_device_release(solo_enc->vfd);
+pci_free:
+	pci_free_consistent(solo_enc->solo_dev->pdev,
+			sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts,
+			solo_enc->desc_items, solo_enc->desc_dma);
+hdl_free:
+	v4l2_ctrl_handler_free(hdl);
+	kfree(solo_enc);
+	return ERR_PTR(ret);
+}
+
+static void solo_enc_free(struct solo_enc_dev *solo_enc)
+{
+	if (solo_enc == NULL)
+		return;
+
+	video_unregister_device(solo_enc->vfd);
+	v4l2_ctrl_handler_free(&solo_enc->hdl);
+	kfree(solo_enc);
+}
+
+int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
+{
+	int i;
+
+	init_waitqueue_head(&solo_dev->ring_thread_wait);
+
+	solo_dev->vh_size = sizeof(vop_header);
+	solo_dev->vh_buf = pci_alloc_consistent(solo_dev->pdev,
+						solo_dev->vh_size,
+						&solo_dev->vh_dma);
+	if (solo_dev->vh_buf == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < solo_dev->nr_chans; i++) {
+		solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i, nr);
+		if (IS_ERR(solo_dev->v4l2_enc[i]))
+			break;
+	}
+
+	if (i != solo_dev->nr_chans) {
+		int ret = PTR_ERR(solo_dev->v4l2_enc[i]);
+
+		while (i--)
+			solo_enc_free(solo_dev->v4l2_enc[i]);
+		pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
+				    solo_dev->vh_buf, solo_dev->vh_dma);
+		solo_dev->vh_buf = NULL;
+		return ret;
+	}
+
+	if (solo_dev->type == SOLO_DEV_6010)
+		solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4;
+	else
+		solo_dev->enc_bw_remain = solo_dev->fps * 4 * 5;
+
+	dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n",
+		 solo_dev->v4l2_enc[0]->vfd->num,
+		 solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num);
+
+	return 0;
+}
+
+void solo_enc_v4l2_exit(struct solo_dev *solo_dev)
+{
+	int i;
+
+	for (i = 0; i < solo_dev->nr_chans; i++)
+		solo_enc_free(solo_dev->v4l2_enc[i]);
+
+	if (solo_dev->vh_buf)
+		pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
+			    solo_dev->vh_buf, solo_dev->vh_dma);
+}
diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c
new file mode 100644
index 0000000000000..63ae8a61f6030
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c
@@ -0,0 +1,733 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "solo6x10.h"
+#include "solo6x10-tw28.h"
+
+/* Image size is two fields, SOLO_HW_BPL is one horizontal line in hardware */
+#define SOLO_HW_BPL		2048
+#define solo_vlines(__solo)	(__solo->video_vsize * 2)
+#define solo_image_size(__solo) (solo_bytesperline(__solo) * \
+				 solo_vlines(__solo))
+#define solo_bytesperline(__solo) (__solo->video_hsize * 2)
+
+#define MIN_VID_BUFFERS		2
+
+static inline void erase_on(struct solo_dev *solo_dev)
+{
+	solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
+	solo_dev->erasing = 1;
+	solo_dev->frame_blank = 0;
+}
+
+static inline int erase_off(struct solo_dev *solo_dev)
+{
+	if (!solo_dev->erasing)
+		return 0;
+
+	/* First time around, assert erase off */
+	if (!solo_dev->frame_blank)
+		solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0);
+	/* Keep the erasing flag on for 8 frames minimum */
+	if (solo_dev->frame_blank++ >= 8)
+		solo_dev->erasing = 0;
+
+	return 1;
+}
+
+void solo_video_in_isr(struct solo_dev *solo_dev)
+{
+	wake_up_interruptible_all(&solo_dev->disp_thread_wait);
+}
+
+static void solo_win_setup(struct solo_dev *solo_dev, u8 ch,
+			   int sx, int sy, int ex, int ey, int scale)
+{
+	if (ch >= solo_dev->nr_chans)
+		return;
+
+	/* Here, we just keep window/channel the same */
+	solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch),
+		       SOLO_VI_WIN_CHANNEL(ch) |
+		       SOLO_VI_WIN_SX(sx) |
+		       SOLO_VI_WIN_EX(ex) |
+		       SOLO_VI_WIN_SCALE(scale));
+
+	solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
+		       SOLO_VI_WIN_SY(sy) |
+		       SOLO_VI_WIN_EY(ey));
+}
+
+static int solo_v4l2_ch_ext_4up(struct solo_dev *solo_dev, u8 idx, int on)
+{
+	u8 ch = idx * 4;
+
+	if (ch >= solo_dev->nr_chans)
+		return -EINVAL;
+
+	if (!on) {
+		u8 i;
+
+		for (i = ch; i < ch + 4; i++)
+			solo_win_setup(solo_dev, i, solo_dev->video_hsize,
+				       solo_vlines(solo_dev),
+				       solo_dev->video_hsize,
+				       solo_vlines(solo_dev), 0);
+		return 0;
+	}
+
+	/* Row 1 */
+	solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2,
+		       solo_vlines(solo_dev) / 2, 3);
+	solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0,
+		       solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3);
+	/* Row 2 */
+	solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2,
+		       solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3);
+	solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2,
+		       solo_vlines(solo_dev) / 2, solo_dev->video_hsize,
+		       solo_vlines(solo_dev), 3);
+
+	return 0;
+}
+
+static int solo_v4l2_ch_ext_16up(struct solo_dev *solo_dev, int on)
+{
+	int sy, ysize, hsize, i;
+
+	if (!on) {
+		for (i = 0; i < 16; i++)
+			solo_win_setup(solo_dev, i, solo_dev->video_hsize,
+				       solo_vlines(solo_dev),
+				       solo_dev->video_hsize,
+				       solo_vlines(solo_dev), 0);
+		return 0;
+	}
+
+	ysize = solo_vlines(solo_dev) / 4;
+	hsize = solo_dev->video_hsize / 4;
+
+	for (sy = 0, i = 0; i < 4; i++, sy += ysize) {
+		solo_win_setup(solo_dev, i * 4, 0, sy, hsize,
+			       sy + ysize, 5);
+		solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy,
+			       hsize * 2, sy + ysize, 5);
+		solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy,
+			       hsize * 3, sy + ysize, 5);
+		solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy,
+			       solo_dev->video_hsize, sy + ysize, 5);
+	}
+
+	return 0;
+}
+
+static int solo_v4l2_ch(struct solo_dev *solo_dev, u8 ch, int on)
+{
+	u8 ext_ch;
+
+	if (ch < solo_dev->nr_chans) {
+		solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize,
+			       on ? 0 : solo_vlines(solo_dev),
+			       solo_dev->video_hsize, solo_vlines(solo_dev),
+			       on ? 1 : 0);
+		return 0;
+	}
+
+	if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
+		return -EINVAL;
+
+	ext_ch = ch - solo_dev->nr_chans;
+
+	/* 4up's first */
+	if (ext_ch < 4)
+		return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on);
+
+	/* Remaining case is 16up for 16-port */
+	return solo_v4l2_ch_ext_16up(solo_dev, on);
+}
+
+static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch)
+{
+	if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
+		return -EINVAL;
+
+	erase_on(solo_dev);
+
+	solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0);
+	solo_v4l2_ch(solo_dev, ch, 1);
+
+	solo_dev->cur_disp_ch = ch;
+
+	return 0;
+}
+
+static void solo_fillbuf(struct solo_dev *solo_dev,
+			 struct vb2_buffer *vb)
+{
+	dma_addr_t vbuf;
+	unsigned int fdma_addr;
+	int error = -1;
+	int i;
+
+	vbuf = vb2_dma_contig_plane_dma_addr(vb, 0);
+	if (!vbuf)
+		goto finish_buf;
+
+	if (erase_off(solo_dev)) {
+		void *p = vb2_plane_vaddr(vb, 0);
+		int image_size = solo_image_size(solo_dev);
+
+		for (i = 0; i < image_size; i += 2) {
+			((u8 *)p)[i] = 0x80;
+			((u8 *)p)[i + 1] = 0x00;
+		}
+		error = 0;
+	} else {
+		fdma_addr = SOLO_DISP_EXT_ADDR + (solo_dev->old_write *
+				(SOLO_HW_BPL * solo_vlines(solo_dev)));
+
+		error = solo_p2m_dma_t(solo_dev, 0, vbuf, fdma_addr,
+				       solo_bytesperline(solo_dev),
+				       solo_vlines(solo_dev), SOLO_HW_BPL);
+	}
+
+finish_buf:
+	if (!error) {
+		vb2_set_plane_payload(vb, 0,
+			solo_vlines(solo_dev) * solo_bytesperline(solo_dev));
+		vb->v4l2_buf.sequence = solo_dev->sequence++;
+		v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
+	}
+
+	vb2_buffer_done(vb, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+}
+
+static void solo_thread_try(struct solo_dev *solo_dev)
+{
+	struct solo_vb2_buf *vb;
+
+	/* Only "break" from this loop if slock is held, otherwise
+	 * just return. */
+	for (;;) {
+		unsigned int cur_write;
+
+		cur_write = SOLO_VI_STATUS0_PAGE(
+			solo_reg_read(solo_dev, SOLO_VI_STATUS0));
+		if (cur_write == solo_dev->old_write)
+			return;
+
+		spin_lock(&solo_dev->slock);
+
+		if (list_empty(&solo_dev->vidq_active))
+			break;
+
+		vb = list_first_entry(&solo_dev->vidq_active, struct solo_vb2_buf,
+				      list);
+
+		solo_dev->old_write = cur_write;
+		list_del(&vb->list);
+
+		spin_unlock(&solo_dev->slock);
+
+		solo_fillbuf(solo_dev, &vb->vb);
+	}
+
+	assert_spin_locked(&solo_dev->slock);
+	spin_unlock(&solo_dev->slock);
+}
+
+static int solo_thread(void *data)
+{
+	struct solo_dev *solo_dev = data;
+	DECLARE_WAITQUEUE(wait, current);
+
+	set_freezable();
+	add_wait_queue(&solo_dev->disp_thread_wait, &wait);
+
+	for (;;) {
+		long timeout = schedule_timeout_interruptible(HZ);
+
+		if (timeout == -ERESTARTSYS || kthread_should_stop())
+			break;
+		solo_thread_try(solo_dev);
+		try_to_freeze();
+	}
+
+	remove_wait_queue(&solo_dev->disp_thread_wait, &wait);
+
+	return 0;
+}
+
+static int solo_start_thread(struct solo_dev *solo_dev)
+{
+	int ret = 0;
+
+	solo_dev->kthread = kthread_run(solo_thread, solo_dev, SOLO6X10_NAME "_disp");
+
+	if (IS_ERR(solo_dev->kthread)) {
+		ret = PTR_ERR(solo_dev->kthread);
+		solo_dev->kthread = NULL;
+		return ret;
+	}
+	solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
+
+	return ret;
+}
+
+static void solo_stop_thread(struct solo_dev *solo_dev)
+{
+	if (!solo_dev->kthread)
+		return;
+
+	solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
+	kthread_stop(solo_dev->kthread);
+	solo_dev->kthread = NULL;
+}
+
+static int solo_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+			   unsigned int *num_buffers, unsigned int *num_planes,
+			   unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct solo_dev *solo_dev = vb2_get_drv_priv(q);
+
+	sizes[0] = solo_image_size(solo_dev);
+	alloc_ctxs[0] = solo_dev->alloc_ctx;
+	*num_planes = 1;
+
+	if (*num_buffers < MIN_VID_BUFFERS)
+		*num_buffers = MIN_VID_BUFFERS;
+
+	return 0;
+}
+
+static int solo_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct solo_dev *solo_dev = vb2_get_drv_priv(q);
+
+	solo_dev->sequence = 0;
+	return solo_start_thread(solo_dev);
+}
+
+static void solo_stop_streaming(struct vb2_queue *q)
+{
+	struct solo_dev *solo_dev = vb2_get_drv_priv(q);
+
+	solo_stop_thread(solo_dev);
+	INIT_LIST_HEAD(&solo_dev->vidq_active);
+}
+
+static void solo_buf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct solo_dev *solo_dev = vb2_get_drv_priv(vq);
+	struct solo_vb2_buf *solo_vb =
+		container_of(vb, struct solo_vb2_buf, vb);
+
+	spin_lock(&solo_dev->slock);
+	list_add_tail(&solo_vb->list, &solo_dev->vidq_active);
+	spin_unlock(&solo_dev->slock);
+	wake_up_interruptible(&solo_dev->disp_thread_wait);
+}
+
+static const struct vb2_ops solo_video_qops = {
+	.queue_setup	= solo_queue_setup,
+	.buf_queue	= solo_buf_queue,
+	.start_streaming = solo_start_streaming,
+	.stop_streaming = solo_stop_streaming,
+	.wait_prepare	= vb2_ops_wait_prepare,
+	.wait_finish	= vb2_ops_wait_finish,
+};
+
+static int solo_querycap(struct file *file, void  *priv,
+			 struct v4l2_capability *cap)
+{
+	struct solo_dev *solo_dev = video_drvdata(file);
+
+	strcpy(cap->driver, SOLO6X10_NAME);
+	strcpy(cap->card, "Softlogic 6x10");
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
+		 pci_name(solo_dev->pdev));
+	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
+			V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int solo_enum_ext_input(struct solo_dev *solo_dev,
+			       struct v4l2_input *input)
+{
+	static const char * const dispnames_1[] = { "4UP" };
+	static const char * const dispnames_2[] = { "4UP-1", "4UP-2" };
+	static const char * const dispnames_5[] = {
+		"4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP"
+	};
+	const char * const *dispnames;
+
+	if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext))
+		return -EINVAL;
+
+	if (solo_dev->nr_ext == 5)
+		dispnames = dispnames_5;
+	else if (solo_dev->nr_ext == 2)
+		dispnames = dispnames_2;
+	else
+		dispnames = dispnames_1;
+
+	snprintf(input->name, sizeof(input->name), "Multi %s",
+		 dispnames[input->index - solo_dev->nr_chans]);
+
+	return 0;
+}
+
+static int solo_enum_input(struct file *file, void *priv,
+			   struct v4l2_input *input)
+{
+	struct solo_dev *solo_dev = video_drvdata(file);
+
+	if (input->index >= solo_dev->nr_chans) {
+		int ret = solo_enum_ext_input(solo_dev, input);
+
+		if (ret < 0)
+			return ret;
+	} else {
+		snprintf(input->name, sizeof(input->name), "Camera %d",
+			 input->index + 1);
+
+		/* We can only check this for normal inputs */
+		if (!tw28_get_video_status(solo_dev, input->index))
+			input->status = V4L2_IN_ST_NO_SIGNAL;
+	}
+
+	input->type = V4L2_INPUT_TYPE_CAMERA;
+	input->std = solo_dev->vfd->tvnorms;
+	return 0;
+}
+
+static int solo_set_input(struct file *file, void *priv, unsigned int index)
+{
+	struct solo_dev *solo_dev = video_drvdata(file);
+	int ret = solo_v4l2_set_ch(solo_dev, index);
+
+	if (!ret) {
+		while (erase_off(solo_dev))
+			/* Do nothing */;
+	}
+
+	return ret;
+}
+
+static int solo_get_input(struct file *file, void *priv, unsigned int *index)
+{
+	struct solo_dev *solo_dev = video_drvdata(file);
+
+	*index = solo_dev->cur_disp_ch;
+
+	return 0;
+}
+
+static int solo_enum_fmt_cap(struct file *file, void *priv,
+			     struct v4l2_fmtdesc *f)
+{
+	if (f->index)
+		return -EINVAL;
+
+	f->pixelformat = V4L2_PIX_FMT_UYVY;
+	strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));
+
+	return 0;
+}
+
+static int solo_try_fmt_cap(struct file *file, void *priv,
+			    struct v4l2_format *f)
+{
+	struct solo_dev *solo_dev = video_drvdata(file);
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	int image_size = solo_image_size(solo_dev);
+
+	if (pix->pixelformat != V4L2_PIX_FMT_UYVY)
+		return -EINVAL;
+
+	pix->width = solo_dev->video_hsize;
+	pix->height = solo_vlines(solo_dev);
+	pix->sizeimage = image_size;
+	pix->field = V4L2_FIELD_INTERLACED;
+	pix->pixelformat = V4L2_PIX_FMT_UYVY;
+	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	pix->priv = 0;
+	return 0;
+}
+
+static int solo_set_fmt_cap(struct file *file, void *priv,
+			    struct v4l2_format *f)
+{
+	struct solo_dev *solo_dev = video_drvdata(file);
+
+	if (vb2_is_busy(&solo_dev->vidq))
+		return -EBUSY;
+
+	/* For right now, if it doesn't match our running config,
+	 * then fail */
+	return solo_try_fmt_cap(file, priv, f);
+}
+
+static int solo_get_fmt_cap(struct file *file, void *priv,
+			    struct v4l2_format *f)
+{
+	struct solo_dev *solo_dev = video_drvdata(file);
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+
+	pix->width = solo_dev->video_hsize;
+	pix->height = solo_vlines(solo_dev);
+	pix->pixelformat = V4L2_PIX_FMT_UYVY;
+	pix->field = V4L2_FIELD_INTERLACED;
+	pix->sizeimage = solo_image_size(solo_dev);
+	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	pix->bytesperline = solo_bytesperline(solo_dev);
+	pix->priv = 0;
+
+	return 0;
+}
+
+static int solo_g_std(struct file *file, void *priv, v4l2_std_id *i)
+{
+	struct solo_dev *solo_dev = video_drvdata(file);
+
+	if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
+		*i = V4L2_STD_NTSC_M;
+	else
+		*i = V4L2_STD_PAL;
+	return 0;
+}
+
+int solo_set_video_type(struct solo_dev *solo_dev, bool is_50hz)
+{
+	int i;
+
+	/* Make sure all video nodes are idle */
+	if (vb2_is_busy(&solo_dev->vidq))
+		return -EBUSY;
+	for (i = 0; i < solo_dev->nr_chans; i++)
+		if (vb2_is_busy(&solo_dev->v4l2_enc[i]->vidq))
+			return -EBUSY;
+	solo_dev->video_type = is_50hz ? SOLO_VO_FMT_TYPE_PAL :
+					 SOLO_VO_FMT_TYPE_NTSC;
+	/* Reconfigure for the new standard */
+	solo_disp_init(solo_dev);
+	solo_enc_init(solo_dev);
+	solo_tw28_init(solo_dev);
+	for (i = 0; i < solo_dev->nr_chans; i++)
+		solo_update_mode(solo_dev->v4l2_enc[i]);
+	return solo_v4l2_set_ch(solo_dev, solo_dev->cur_disp_ch);
+}
+
+static int solo_s_std(struct file *file, void *priv, v4l2_std_id std)
+{
+	struct solo_dev *solo_dev = video_drvdata(file);
+
+	return solo_set_video_type(solo_dev, std & V4L2_STD_625_50);
+}
+
+static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct solo_dev *solo_dev =
+		container_of(ctrl->handler, struct solo_dev, disp_hdl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_MOTION_TRACE:
+		if (ctrl->val) {
+			solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER,
+					SOLO_VI_MOTION_Y_ADD |
+					SOLO_VI_MOTION_Y_VALUE(0x20) |
+					SOLO_VI_MOTION_CB_VALUE(0x10) |
+					SOLO_VI_MOTION_CR_VALUE(0x10));
+			solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR,
+					SOLO_VI_MOTION_CR_ADD |
+					SOLO_VI_MOTION_Y_VALUE(0x10) |
+					SOLO_VI_MOTION_CB_VALUE(0x80) |
+					SOLO_VI_MOTION_CR_VALUE(0x10));
+		} else {
+			solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
+			solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
+		}
+		return 0;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static const struct v4l2_file_operations solo_v4l2_fops = {
+	.owner			= THIS_MODULE,
+	.open			= v4l2_fh_open,
+	.release		= vb2_fop_release,
+	.read			= vb2_fop_read,
+	.poll			= vb2_fop_poll,
+	.mmap			= vb2_fop_mmap,
+	.unlocked_ioctl		= video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
+	.vidioc_querycap		= solo_querycap,
+	.vidioc_s_std			= solo_s_std,
+	.vidioc_g_std			= solo_g_std,
+	/* Input callbacks */
+	.vidioc_enum_input		= solo_enum_input,
+	.vidioc_s_input			= solo_set_input,
+	.vidioc_g_input			= solo_get_input,
+	/* Video capture format callbacks */
+	.vidioc_enum_fmt_vid_cap	= solo_enum_fmt_cap,
+	.vidioc_try_fmt_vid_cap		= solo_try_fmt_cap,
+	.vidioc_s_fmt_vid_cap		= solo_set_fmt_cap,
+	.vidioc_g_fmt_vid_cap		= solo_get_fmt_cap,
+	/* Streaming I/O */
+	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
+	.vidioc_querybuf		= vb2_ioctl_querybuf,
+	.vidioc_qbuf			= vb2_ioctl_qbuf,
+	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
+	.vidioc_streamon		= vb2_ioctl_streamon,
+	.vidioc_streamoff		= vb2_ioctl_streamoff,
+	/* Logging and events */
+	.vidioc_log_status		= v4l2_ctrl_log_status,
+	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
+};
+
+static struct video_device solo_v4l2_template = {
+	.name			= SOLO6X10_NAME,
+	.fops			= &solo_v4l2_fops,
+	.ioctl_ops		= &solo_v4l2_ioctl_ops,
+	.minor			= -1,
+	.release		= video_device_release,
+	.tvnorms		= V4L2_STD_NTSC_M | V4L2_STD_PAL,
+};
+
+static const struct v4l2_ctrl_ops solo_ctrl_ops = {
+	.s_ctrl = solo_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config solo_motion_trace_ctrl = {
+	.ops = &solo_ctrl_ops,
+	.id = V4L2_CID_MOTION_TRACE,
+	.name = "Motion Detection Trace",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.step = 1,
+};
+
+int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
+{
+	int ret;
+	int i;
+
+	init_waitqueue_head(&solo_dev->disp_thread_wait);
+	spin_lock_init(&solo_dev->slock);
+	mutex_init(&solo_dev->lock);
+	INIT_LIST_HEAD(&solo_dev->vidq_active);
+
+	solo_dev->vfd = video_device_alloc();
+	if (!solo_dev->vfd)
+		return -ENOMEM;
+
+	*solo_dev->vfd = solo_v4l2_template;
+	solo_dev->vfd->v4l2_dev = &solo_dev->v4l2_dev;
+	solo_dev->vfd->queue = &solo_dev->vidq;
+	solo_dev->vfd->lock = &solo_dev->lock;
+	v4l2_ctrl_handler_init(&solo_dev->disp_hdl, 1);
+	v4l2_ctrl_new_custom(&solo_dev->disp_hdl, &solo_motion_trace_ctrl, NULL);
+	if (solo_dev->disp_hdl.error) {
+		ret = solo_dev->disp_hdl.error;
+		goto fail;
+	}
+	solo_dev->vfd->ctrl_handler = &solo_dev->disp_hdl;
+
+	video_set_drvdata(solo_dev->vfd, solo_dev);
+
+	solo_dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	solo_dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+	solo_dev->vidq.ops = &solo_video_qops;
+	solo_dev->vidq.mem_ops = &vb2_dma_contig_memops;
+	solo_dev->vidq.drv_priv = solo_dev;
+	solo_dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	solo_dev->vidq.gfp_flags = __GFP_DMA32;
+	solo_dev->vidq.buf_struct_size = sizeof(struct solo_vb2_buf);
+	solo_dev->vidq.lock = &solo_dev->lock;
+	ret = vb2_queue_init(&solo_dev->vidq);
+	if (ret < 0)
+		goto fail;
+
+	solo_dev->alloc_ctx = vb2_dma_contig_init_ctx(&solo_dev->pdev->dev);
+	if (IS_ERR(solo_dev->alloc_ctx)) {
+		dev_err(&solo_dev->pdev->dev, "Can't allocate buffer context");
+		return PTR_ERR(solo_dev->alloc_ctx);
+	}
+
+	/* Cycle all the channels and clear */
+	for (i = 0; i < solo_dev->nr_chans; i++) {
+		solo_v4l2_set_ch(solo_dev, i);
+		while (erase_off(solo_dev))
+			/* Do nothing */;
+	}
+
+	/* Set the default display channel */
+	solo_v4l2_set_ch(solo_dev, 0);
+	while (erase_off(solo_dev))
+		/* Do nothing */;
+
+	ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr);
+	if (ret < 0)
+		goto fail;
+
+	snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
+		 SOLO6X10_NAME, solo_dev->vfd->num);
+
+	dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with "
+		 "%d inputs (%d extended)\n", solo_dev->vfd->num,
+		 solo_dev->nr_chans, solo_dev->nr_ext);
+
+	return 0;
+
+fail:
+	video_device_release(solo_dev->vfd);
+	vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx);
+	v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
+	solo_dev->vfd = NULL;
+	return ret;
+}
+
+void solo_v4l2_exit(struct solo_dev *solo_dev)
+{
+	if (solo_dev->vfd == NULL)
+		return;
+
+	video_unregister_device(solo_dev->vfd);
+	vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx);
+	v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
+	solo_dev->vfd = NULL;
+}
diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h
new file mode 100644
index 0000000000000..c6154b00fcbd9
--- /dev/null
+++ b/drivers/media/pci/solo6x10/solo6x10.h
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * 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.
+ */
+
+#ifndef __SOLO6X10_H
+#define __SOLO6X10_H
+
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/stringify.h>
+#include <linux/io.h>
+#include <linux/atomic.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+
+#include "solo6x10-regs.h"
+
+#ifndef PCI_VENDOR_ID_SOFTLOGIC
+#define PCI_VENDOR_ID_SOFTLOGIC		0x9413
+#define PCI_DEVICE_ID_SOLO6010		0x6010
+#define PCI_DEVICE_ID_SOLO6110		0x6110
+#endif
+
+#ifndef PCI_VENDOR_ID_BLUECHERRY
+#define PCI_VENDOR_ID_BLUECHERRY	0x1BB3
+/* Neugent Softlogic 6010 based cards */
+#define PCI_DEVICE_ID_NEUSOLO_4		0x4304
+#define PCI_DEVICE_ID_NEUSOLO_9		0x4309
+#define PCI_DEVICE_ID_NEUSOLO_16	0x4310
+/* Bluecherry Softlogic 6010 based cards */
+#define PCI_DEVICE_ID_BC_SOLO_4		0x4E04
+#define PCI_DEVICE_ID_BC_SOLO_9		0x4E09
+#define PCI_DEVICE_ID_BC_SOLO_16	0x4E10
+/* Bluecherry Softlogic 6110 based cards */
+#define PCI_DEVICE_ID_BC_6110_4		0x5304
+#define PCI_DEVICE_ID_BC_6110_8		0x5308
+#define PCI_DEVICE_ID_BC_6110_16	0x5310
+#endif /* Bluecherry */
+
+/* Used in pci_device_id, and solo_dev->type */
+#define SOLO_DEV_6010			0
+#define SOLO_DEV_6110			1
+
+#define SOLO6X10_NAME			"solo6x10"
+
+#define SOLO_MAX_CHANNELS		16
+
+#define SOLO6X10_VERSION		"3.0.0"
+
+/*
+ * The SOLO6x10 actually has 8 i2c channels, but we only use 2.
+ * 0 - Techwell chip(s)
+ * 1 - SAA7128
+ */
+#define SOLO_I2C_ADAPTERS		2
+#define SOLO_I2C_TW			0
+#define SOLO_I2C_SAA			1
+
+/* DMA Engine setup */
+#define SOLO_NR_P2M			4
+#define SOLO_NR_P2M_DESC		256
+#define SOLO_P2M_DESC_SIZE		(SOLO_NR_P2M_DESC * 16)
+
+/* Encoder standard modes */
+#define SOLO_ENC_MODE_CIF		2
+#define SOLO_ENC_MODE_HD1		1
+#define SOLO_ENC_MODE_D1		9
+
+#define SOLO_DEFAULT_QP			3
+
+#define SOLO_CID_CUSTOM_BASE		(V4L2_CID_USER_BASE | 0xf000)
+#define V4L2_CID_MOTION_TRACE		(SOLO_CID_CUSTOM_BASE+2)
+#define V4L2_CID_OSD_TEXT		(SOLO_CID_CUSTOM_BASE+3)
+
+/*
+ * Motion thresholds are in a table of 64x64 samples, with
+ * each sample representing 16x16 pixels of the source. In
+ * effect, 44x30 samples are used for NTSC, and 44x36 for PAL.
+ * The 5th sample on the 10th row is (10*64)+5 = 645.
+ *
+ * Internally it is stored as a 45x45 array (45*16 = 720, which is the
+ * maximum PAL/NTSC width).
+ */
+#define SOLO_MOTION_SZ (45)
+
+enum SOLO_I2C_STATE {
+	IIC_STATE_IDLE,
+	IIC_STATE_START,
+	IIC_STATE_READ,
+	IIC_STATE_WRITE,
+	IIC_STATE_STOP
+};
+
+/* Defined in Table 4-16, Page 68-69 of the 6010 Datasheet */
+struct solo_p2m_desc {
+	u32	ctrl;
+	u32	cfg;
+	u32	dma_addr;
+	u32	ext_addr;
+};
+
+struct solo_p2m_dev {
+	struct mutex		mutex;
+	struct completion	completion;
+	int			desc_count;
+	int			desc_idx;
+	struct solo_p2m_desc	*descs;
+	int			error;
+};
+
+#define OSD_TEXT_MAX		44
+
+struct solo_vb2_buf {
+	struct vb2_buffer vb;
+	struct list_head list;
+};
+
+enum solo_enc_types {
+	SOLO_ENC_TYPE_STD,
+	SOLO_ENC_TYPE_EXT,
+};
+
+struct solo_enc_dev {
+	struct solo_dev	*solo_dev;
+	/* V4L2 Items */
+	struct v4l2_ctrl_handler hdl;
+	struct v4l2_ctrl *md_thresholds;
+	struct video_device	*vfd;
+	/* General accounting */
+	struct mutex		lock;
+	spinlock_t		motion_lock;
+	u8			ch;
+	u8			mode, gop, qp, interlaced, interval;
+	u8			bw_weight;
+	u16			motion_thresh;
+	bool			motion_global;
+	bool			motion_enabled;
+	bool			motion_last_state;
+	u8			frames_since_last_motion;
+	u16			width;
+	u16			height;
+
+	/* OSD buffers */
+	char			osd_text[OSD_TEXT_MAX + 1];
+	u8			osd_buf[SOLO_EOSD_EXT_SIZE_MAX]
+					__aligned(4);
+
+	/* VOP stuff */
+	unsigned char		vop[64];
+	int			vop_len;
+	unsigned char		jpeg_header[1024];
+	int			jpeg_len;
+
+	u32			fmt;
+	enum solo_enc_types	type;
+	u32			sequence;
+	struct vb2_queue	vidq;
+	struct list_head	vidq_active;
+	int			desc_count;
+	int			desc_nelts;
+	struct solo_p2m_desc	*desc_items;
+	dma_addr_t		desc_dma;
+	spinlock_t		av_lock;
+};
+
+/* The SOLO6x10 PCI Device */
+struct solo_dev {
+	/* General stuff */
+	struct pci_dev		*pdev;
+	int			type;
+	unsigned int		time_sync;
+	unsigned int		usec_lsb;
+	unsigned int		clock_mhz;
+	u8 __iomem		*reg_base;
+	int			nr_chans;
+	int			nr_ext;
+	u32			irq_mask;
+	u32			motion_mask;
+	spinlock_t		reg_io_lock;
+	struct v4l2_device	v4l2_dev;
+
+	/* tw28xx accounting */
+	u8			tw2865, tw2864, tw2815;
+	u8			tw28_cnt;
+
+	/* i2c related items */
+	struct i2c_adapter	i2c_adap[SOLO_I2C_ADAPTERS];
+	enum SOLO_I2C_STATE	i2c_state;
+	struct mutex		i2c_mutex;
+	int			i2c_id;
+	wait_queue_head_t	i2c_wait;
+	struct i2c_msg		*i2c_msg;
+	unsigned int		i2c_msg_num;
+	unsigned int		i2c_msg_ptr;
+
+	/* P2M DMA Engine */
+	struct solo_p2m_dev	p2m_dev[SOLO_NR_P2M];
+	atomic_t		p2m_count;
+	int			p2m_jiffies;
+	unsigned int		p2m_timeouts;
+
+	/* V4L2 Display items */
+	struct video_device	*vfd;
+	unsigned int		erasing;
+	unsigned int		frame_blank;
+	u8			cur_disp_ch;
+	wait_queue_head_t	disp_thread_wait;
+	struct v4l2_ctrl_handler disp_hdl;
+
+	/* V4L2 Encoder items */
+	struct solo_enc_dev	*v4l2_enc[SOLO_MAX_CHANNELS];
+	u16			enc_bw_remain;
+	/* IDX into hw mp4 encoder */
+	u8			enc_idx;
+
+	/* Current video settings */
+	u32			video_type;
+	u16			video_hsize, video_vsize;
+	u16			vout_hstart, vout_vstart;
+	u16			vin_hstart, vin_vstart;
+	u8			fps;
+
+	/* JPEG Qp setting */
+	spinlock_t      jpeg_qp_lock;
+	u32		jpeg_qp[2];
+
+	/* Audio components */
+	struct snd_card		*snd_card;
+	struct snd_pcm		*snd_pcm;
+	atomic_t		snd_users;
+	int			g723_hw_idx;
+
+	/* sysfs stuffs */
+	struct device		dev;
+	int			sdram_size;
+	struct bin_attribute	sdram_attr;
+	unsigned int		sys_config;
+
+	/* Ring thread */
+	struct task_struct	*ring_thread;
+	wait_queue_head_t	ring_thread_wait;
+
+	/* VOP_HEADER handling */
+	void                    *vh_buf;
+	dma_addr_t		vh_dma;
+	int			vh_size;
+
+	/* Buffer handling */
+	struct vb2_queue	vidq;
+	struct vb2_alloc_ctx	*alloc_ctx;
+	u32			sequence;
+	struct task_struct      *kthread;
+	struct mutex		lock;
+	spinlock_t		slock;
+	int			old_write;
+	struct list_head	vidq_active;
+};
+
+static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg)
+{
+	unsigned long flags;
+	u32 ret;
+	u16 val;
+
+	spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
+
+	ret = readl(solo_dev->reg_base + reg);
+	rmb();
+	pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
+	rmb();
+
+	spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
+
+	return ret;
+}
+
+static inline void solo_reg_write(struct solo_dev *solo_dev, int reg,
+				  u32 data)
+{
+	unsigned long flags;
+	u16 val;
+
+	spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
+
+	writel(data, solo_dev->reg_base + reg);
+	wmb();
+	pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
+	rmb();
+
+	spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
+}
+
+static inline void solo_irq_on(struct solo_dev *dev, u32 mask)
+{
+	dev->irq_mask |= mask;
+	solo_reg_write(dev, SOLO_IRQ_MASK, dev->irq_mask);
+}
+
+static inline void solo_irq_off(struct solo_dev *dev, u32 mask)
+{
+	dev->irq_mask &= ~mask;
+	solo_reg_write(dev, SOLO_IRQ_MASK, dev->irq_mask);
+}
+
+/* Init/exit routines for subsystems */
+int solo_disp_init(struct solo_dev *solo_dev);
+void solo_disp_exit(struct solo_dev *solo_dev);
+
+int solo_gpio_init(struct solo_dev *solo_dev);
+void solo_gpio_exit(struct solo_dev *solo_dev);
+
+int solo_i2c_init(struct solo_dev *solo_dev);
+void solo_i2c_exit(struct solo_dev *solo_dev);
+
+int solo_p2m_init(struct solo_dev *solo_dev);
+void solo_p2m_exit(struct solo_dev *solo_dev);
+
+int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr);
+void solo_v4l2_exit(struct solo_dev *solo_dev);
+
+int solo_enc_init(struct solo_dev *solo_dev);
+void solo_enc_exit(struct solo_dev *solo_dev);
+
+int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr);
+void solo_enc_v4l2_exit(struct solo_dev *solo_dev);
+
+int solo_g723_init(struct solo_dev *solo_dev);
+void solo_g723_exit(struct solo_dev *solo_dev);
+
+/* ISR's */
+int solo_i2c_isr(struct solo_dev *solo_dev);
+void solo_p2m_isr(struct solo_dev *solo_dev, int id);
+void solo_p2m_error_isr(struct solo_dev *solo_dev);
+void solo_enc_v4l2_isr(struct solo_dev *solo_dev);
+void solo_g723_isr(struct solo_dev *solo_dev);
+void solo_motion_isr(struct solo_dev *solo_dev);
+void solo_video_in_isr(struct solo_dev *solo_dev);
+
+/* i2c read/write */
+u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off);
+void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off,
+			u8 data);
+
+/* P2M DMA */
+int solo_p2m_dma_t(struct solo_dev *solo_dev, int wr,
+		   dma_addr_t dma_addr, u32 ext_addr, u32 size,
+		   int repeat, u32 ext_size);
+int solo_p2m_dma(struct solo_dev *solo_dev, int wr,
+		 void *sys_addr, u32 ext_addr, u32 size,
+		 int repeat, u32 ext_size);
+void solo_p2m_fill_desc(struct solo_p2m_desc *desc, int wr,
+			dma_addr_t dma_addr, u32 ext_addr, u32 size,
+			int repeat, u32 ext_size);
+int solo_p2m_dma_desc(struct solo_dev *solo_dev,
+		      struct solo_p2m_desc *desc, dma_addr_t desc_dma,
+		      int desc_cnt);
+
+/* Global s_std ioctl */
+int solo_set_video_type(struct solo_dev *solo_dev, bool is_50hz);
+void solo_update_mode(struct solo_enc_dev *solo_enc);
+
+/* Set the threshold for motion detection */
+int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val);
+int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
+		const u16 *thresholds);
+#define SOLO_DEF_MOT_THRESH		0x0300
+
+/* Write text on OSD */
+int solo_osd_print(struct solo_enc_dev *solo_enc);
+
+/* EEPROM commands */
+unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en);
+unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc);
+int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
+		      unsigned short data);
+
+/* JPEG Qp functions */
+void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch,
+		    unsigned int qp);
+int solo_g_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch);
+
+#define CHK_FLAGS(v, flags) (((v) & (flags)) == (flags))
+
+#endif /* __SOLO6X10_H */
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index e91c538d3d0d0..3312a3bd256d5 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -33,8 +33,6 @@ source "drivers/staging/media/go7007/Kconfig"
 
 source "drivers/staging/media/omap24xx/Kconfig"
 
-source "drivers/staging/media/solo6x10/Kconfig"
-
 source "drivers/staging/media/omap4iss/Kconfig"
 
 # Keep LIRC at the end, as it has sub-menus
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index 4f6c0ee0ad131..205eba2833260 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -2,7 +2,6 @@ obj-$(CONFIG_DVB_AS102)		+= as102/
 obj-$(CONFIG_I2C_BCM2048)	+= bcm2048/
 obj-$(CONFIG_DVB_CXD2099)	+= cxd2099/
 obj-$(CONFIG_LIRC_STAGING)	+= lirc/
-obj-$(CONFIG_SOLO6X10)		+= solo6x10/
 obj-$(CONFIG_VIDEO_DT3155)	+= dt3155v4l/
 obj-$(CONFIG_VIDEO_GO7007)	+= go7007/
 obj-$(CONFIG_VIDEO_DM365_VPFE)	+= davinci_vpfe/
diff --git a/drivers/staging/media/solo6x10/Kconfig b/drivers/staging/media/solo6x10/Kconfig
deleted file mode 100644
index 1ce2819efcb4a..0000000000000
--- a/drivers/staging/media/solo6x10/Kconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-config SOLO6X10
-	tristate "Bluecherry / Softlogic 6x10 capture cards (MPEG-4/H.264)"
-	depends on PCI && VIDEO_DEV && SND && I2C
-	select BITREVERSE
-	select FONT_SUPPORT
-	select FONT_8x16
-	select VIDEOBUF2_DMA_SG
-	select VIDEOBUF2_DMA_CONTIG
-	select SND_PCM
-	select FONT_8x16
-	---help---
-	  This driver supports the Bluecherry H.264 and MPEG-4 hardware
-	  compression capture cards and other Softlogic-based ones.
-
-	  Following cards have been tested:
-	  * Bluecherry BC-H16480A (PCIe, 16 port, H.264)
-	  * Bluecherry BC-H04120A (PCIe, 4 port, H.264)
-	  * Bluecherry BC-H04120A-MPCI (Mini-PCI, 4 port, H.264)
-	  * Bluecherry BC-04120A (PCIe, 4 port, MPEG-4)
diff --git a/drivers/staging/media/solo6x10/Makefile b/drivers/staging/media/solo6x10/Makefile
deleted file mode 100644
index 7aae118947b23..0000000000000
--- a/drivers/staging/media/solo6x10/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-solo6x10-y := solo6x10-core.o solo6x10-i2c.o solo6x10-p2m.o solo6x10-v4l2.o \
-		solo6x10-tw28.o solo6x10-gpio.o solo6x10-disp.o solo6x10-enc.o \
-		solo6x10-v4l2-enc.o solo6x10-g723.o solo6x10-eeprom.o
-
-obj-$(CONFIG_SOLO6X10) += solo6x10.o
diff --git a/drivers/staging/media/solo6x10/TODO b/drivers/staging/media/solo6x10/TODO
deleted file mode 100644
index 7b8db75b1acba..0000000000000
--- a/drivers/staging/media/solo6x10/TODO
+++ /dev/null
@@ -1,15 +0,0 @@
-- batch up desc requests for more efficient use of p2m?
-- encoder on/off controls
-- mpeg cid bitrate mode (vbr/cbr)
-- mpeg cid bitrate/bitrate-peak
-- mpeg encode of user data
-- mpeg decode of user data
-- implement CID controls for mozaic areas
-
-- sound
- - implement playback via external sound jack
- - implement loopback of external sound jack with incoming audio?
- - implement pause/resume (make use of in bc-server)
-
-Please send patches to the linux media list <linux-media@vger.kernel.org> and
-Cc Ismael Luceno <ismael.luceno@corp.bluecherry.net>.
diff --git a/drivers/staging/media/solo6x10/solo6x10-core.c b/drivers/staging/media/solo6x10/solo6x10-core.c
deleted file mode 100644
index 172583d736fef..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10-core.c
+++ /dev/null
@@ -1,705 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/videodev2.h>
-#include <linux/delay.h>
-#include <linux/sysfs.h>
-#include <linux/ktime.h>
-#include <linux/slab.h>
-
-#include "solo6x10.h"
-#include "solo6x10-tw28.h"
-
-MODULE_DESCRIPTION("Softlogic 6x10 MPEG4/H.264/G.723 CODEC V4L2/ALSA Driver");
-MODULE_AUTHOR("Bluecherry <maintainers@bluecherrydvr.com>");
-MODULE_VERSION(SOLO6X10_VERSION);
-MODULE_LICENSE("GPL");
-
-static unsigned video_nr = -1;
-module_param(video_nr, uint, 0644);
-MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)");
-
-static int full_eeprom; /* default is only top 64B */
-module_param(full_eeprom, uint, 0644);
-MODULE_PARM_DESC(full_eeprom, "Allow access to full 128B EEPROM (dangerous)");
-
-
-static void solo_set_time(struct solo_dev *solo_dev)
-{
-	struct timespec ts;
-
-	ktime_get_ts(&ts);
-
-	solo_reg_write(solo_dev, SOLO_TIMER_SEC, ts.tv_sec);
-	solo_reg_write(solo_dev, SOLO_TIMER_USEC, ts.tv_nsec / NSEC_PER_USEC);
-}
-
-static void solo_timer_sync(struct solo_dev *solo_dev)
-{
-	u32 sec, usec;
-	struct timespec ts;
-	long diff;
-
-	if (solo_dev->type != SOLO_DEV_6110)
-		return;
-
-	if (++solo_dev->time_sync < 60)
-		return;
-
-	solo_dev->time_sync = 0;
-
-	sec = solo_reg_read(solo_dev, SOLO_TIMER_SEC);
-	usec = solo_reg_read(solo_dev, SOLO_TIMER_USEC);
-
-	ktime_get_ts(&ts);
-
-	diff = (long)ts.tv_sec - (long)sec;
-	diff = (diff * 1000000)
-		+ ((long)(ts.tv_nsec / NSEC_PER_USEC) - (long)usec);
-
-	if (diff > 1000 || diff < -1000) {
-		solo_set_time(solo_dev);
-	} else if (diff) {
-		long usec_lsb = solo_dev->usec_lsb;
-
-		usec_lsb -= diff / 4;
-		if (usec_lsb < 0)
-			usec_lsb = 0;
-		else if (usec_lsb > 255)
-			usec_lsb = 255;
-
-		solo_dev->usec_lsb = usec_lsb;
-		solo_reg_write(solo_dev, SOLO_TIMER_USEC_LSB,
-			       solo_dev->usec_lsb);
-	}
-}
-
-static irqreturn_t solo_isr(int irq, void *data)
-{
-	struct solo_dev *solo_dev = data;
-	u32 status;
-	int i;
-
-	status = solo_reg_read(solo_dev, SOLO_IRQ_STAT);
-	if (!status)
-		return IRQ_NONE;
-
-	if (status & ~solo_dev->irq_mask) {
-		solo_reg_write(solo_dev, SOLO_IRQ_STAT,
-			       status & ~solo_dev->irq_mask);
-		status &= solo_dev->irq_mask;
-	}
-
-	if (status & SOLO_IRQ_PCI_ERR)
-		solo_p2m_error_isr(solo_dev);
-
-	for (i = 0; i < SOLO_NR_P2M; i++)
-		if (status & SOLO_IRQ_P2M(i))
-			solo_p2m_isr(solo_dev, i);
-
-	if (status & SOLO_IRQ_IIC)
-		solo_i2c_isr(solo_dev);
-
-	if (status & SOLO_IRQ_VIDEO_IN) {
-		solo_video_in_isr(solo_dev);
-		solo_timer_sync(solo_dev);
-	}
-
-	if (status & SOLO_IRQ_ENCODER)
-		solo_enc_v4l2_isr(solo_dev);
-
-	if (status & SOLO_IRQ_G723)
-		solo_g723_isr(solo_dev);
-
-	/* Clear all interrupts handled */
-	solo_reg_write(solo_dev, SOLO_IRQ_STAT, status);
-
-	return IRQ_HANDLED;
-}
-
-static void free_solo_dev(struct solo_dev *solo_dev)
-{
-	struct pci_dev *pdev;
-
-	if (!solo_dev)
-		return;
-
-	if (solo_dev->dev.parent)
-		device_unregister(&solo_dev->dev);
-
-	pdev = solo_dev->pdev;
-
-	/* If we never initialized the PCI device, then nothing else
-	 * below here needs cleanup */
-	if (!pdev) {
-		kfree(solo_dev);
-		return;
-	}
-
-	if (solo_dev->reg_base) {
-		/* Bring down the sub-devices first */
-		solo_g723_exit(solo_dev);
-		solo_enc_v4l2_exit(solo_dev);
-		solo_enc_exit(solo_dev);
-		solo_v4l2_exit(solo_dev);
-		solo_disp_exit(solo_dev);
-		solo_gpio_exit(solo_dev);
-		solo_p2m_exit(solo_dev);
-		solo_i2c_exit(solo_dev);
-
-		/* Now cleanup the PCI device */
-		solo_irq_off(solo_dev, ~0);
-		pci_iounmap(pdev, solo_dev->reg_base);
-		if (pdev->irq)
-			free_irq(pdev->irq, solo_dev);
-	}
-
-	pci_release_regions(pdev);
-	pci_disable_device(pdev);
-	v4l2_device_unregister(&solo_dev->v4l2_dev);
-	pci_set_drvdata(pdev, NULL);
-
-	kfree(solo_dev);
-}
-
-static ssize_t eeprom_store(struct device *dev, struct device_attribute *attr,
-			    const char *buf, size_t count)
-{
-	struct solo_dev *solo_dev =
-		container_of(dev, struct solo_dev, dev);
-	unsigned short *p = (unsigned short *)buf;
-	int i;
-
-	if (count & 0x1)
-		dev_warn(dev, "EEPROM Write not aligned (truncating)\n");
-
-	if (!full_eeprom && count > 64) {
-		dev_warn(dev, "EEPROM Write truncated to 64 bytes\n");
-		count = 64;
-	} else if (full_eeprom && count > 128) {
-		dev_warn(dev, "EEPROM Write truncated to 128 bytes\n");
-		count = 128;
-	}
-
-	solo_eeprom_ewen(solo_dev, 1);
-
-	for (i = full_eeprom ? 0 : 32; i < min((int)(full_eeprom ? 64 : 32),
-					       (int)(count / 2)); i++)
-		solo_eeprom_write(solo_dev, i, cpu_to_be16(p[i]));
-
-	solo_eeprom_ewen(solo_dev, 0);
-
-	return count;
-}
-
-static ssize_t eeprom_show(struct device *dev, struct device_attribute *attr,
-			   char *buf)
-{
-	struct solo_dev *solo_dev =
-		container_of(dev, struct solo_dev, dev);
-	unsigned short *p = (unsigned short *)buf;
-	int count = (full_eeprom ? 128 : 64);
-	int i;
-
-	for (i = (full_eeprom ? 0 : 32); i < (count / 2); i++)
-		p[i] = be16_to_cpu(solo_eeprom_read(solo_dev, i));
-
-	return count;
-}
-
-static ssize_t p2m_timeouts_show(struct device *dev,
-				 struct device_attribute *attr,
-				 char *buf)
-{
-	struct solo_dev *solo_dev =
-		container_of(dev, struct solo_dev, dev);
-
-	return sprintf(buf, "%d\n", solo_dev->p2m_timeouts);
-}
-
-static ssize_t sdram_size_show(struct device *dev,
-			       struct device_attribute *attr,
-			       char *buf)
-{
-	struct solo_dev *solo_dev =
-		container_of(dev, struct solo_dev, dev);
-
-	return sprintf(buf, "%dMegs\n", solo_dev->sdram_size >> 20);
-}
-
-static ssize_t tw28xx_show(struct device *dev,
-			   struct device_attribute *attr,
-			   char *buf)
-{
-	struct solo_dev *solo_dev =
-		container_of(dev, struct solo_dev, dev);
-
-	return sprintf(buf, "tw2815[%d] tw2864[%d] tw2865[%d]\n",
-		       hweight32(solo_dev->tw2815),
-		       hweight32(solo_dev->tw2864),
-		       hweight32(solo_dev->tw2865));
-}
-
-static ssize_t input_map_show(struct device *dev,
-			      struct device_attribute *attr,
-			      char *buf)
-{
-	struct solo_dev *solo_dev =
-		container_of(dev, struct solo_dev, dev);
-	unsigned int val;
-	char *out = buf;
-
-	val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_0);
-	out += sprintf(out, "Channel 0   => Input %d\n", val & 0x1f);
-	out += sprintf(out, "Channel 1   => Input %d\n", (val >> 5) & 0x1f);
-	out += sprintf(out, "Channel 2   => Input %d\n", (val >> 10) & 0x1f);
-	out += sprintf(out, "Channel 3   => Input %d\n", (val >> 15) & 0x1f);
-	out += sprintf(out, "Channel 4   => Input %d\n", (val >> 20) & 0x1f);
-	out += sprintf(out, "Channel 5   => Input %d\n", (val >> 25) & 0x1f);
-
-	val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_1);
-	out += sprintf(out, "Channel 6   => Input %d\n", val & 0x1f);
-	out += sprintf(out, "Channel 7   => Input %d\n", (val >> 5) & 0x1f);
-	out += sprintf(out, "Channel 8   => Input %d\n", (val >> 10) & 0x1f);
-	out += sprintf(out, "Channel 9   => Input %d\n", (val >> 15) & 0x1f);
-	out += sprintf(out, "Channel 10  => Input %d\n", (val >> 20) & 0x1f);
-	out += sprintf(out, "Channel 11  => Input %d\n", (val >> 25) & 0x1f);
-
-	val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_2);
-	out += sprintf(out, "Channel 12  => Input %d\n", val & 0x1f);
-	out += sprintf(out, "Channel 13  => Input %d\n", (val >> 5) & 0x1f);
-	out += sprintf(out, "Channel 14  => Input %d\n", (val >> 10) & 0x1f);
-	out += sprintf(out, "Channel 15  => Input %d\n", (val >> 15) & 0x1f);
-	out += sprintf(out, "Spot Output => Input %d\n", (val >> 20) & 0x1f);
-
-	return out - buf;
-}
-
-static ssize_t p2m_timeout_store(struct device *dev,
-				 struct device_attribute *attr,
-				 const char *buf, size_t count)
-{
-	struct solo_dev *solo_dev =
-		container_of(dev, struct solo_dev, dev);
-	unsigned long ms;
-	int ret = kstrtoul(buf, 10, &ms);
-
-	if (ret < 0 || ms > 200)
-		return -EINVAL;
-	solo_dev->p2m_jiffies = msecs_to_jiffies(ms);
-
-	return count;
-}
-
-static ssize_t p2m_timeout_show(struct device *dev,
-				struct device_attribute *attr,
-				char *buf)
-{
-	struct solo_dev *solo_dev =
-		container_of(dev, struct solo_dev, dev);
-
-	return sprintf(buf, "%ums\n", jiffies_to_msecs(solo_dev->p2m_jiffies));
-}
-
-static ssize_t intervals_show(struct device *dev,
-			      struct device_attribute *attr,
-			      char *buf)
-{
-	struct solo_dev *solo_dev =
-		container_of(dev, struct solo_dev, dev);
-	char *out = buf;
-	int fps = solo_dev->fps;
-	int i;
-
-	for (i = 0; i < solo_dev->nr_chans; i++) {
-		out += sprintf(out, "Channel %d: %d/%d (0x%08x)\n",
-			       i, solo_dev->v4l2_enc[i]->interval, fps,
-			       solo_reg_read(solo_dev, SOLO_CAP_CH_INTV(i)));
-	}
-
-	return out - buf;
-}
-
-static ssize_t sdram_offsets_show(struct device *dev,
-				  struct device_attribute *attr,
-				  char *buf)
-{
-	struct solo_dev *solo_dev =
-		container_of(dev, struct solo_dev, dev);
-	char *out = buf;
-
-	out += sprintf(out, "DISP: 0x%08x @ 0x%08x\n",
-		       SOLO_DISP_EXT_ADDR,
-		       SOLO_DISP_EXT_SIZE);
-
-	out += sprintf(out, "EOSD: 0x%08x @ 0x%08x (0x%08x * %d)\n",
-		       SOLO_EOSD_EXT_ADDR,
-		       SOLO_EOSD_EXT_AREA(solo_dev),
-		       SOLO_EOSD_EXT_SIZE(solo_dev),
-		       SOLO_EOSD_EXT_AREA(solo_dev) /
-		       SOLO_EOSD_EXT_SIZE(solo_dev));
-
-	out += sprintf(out, "MOTI: 0x%08x @ 0x%08x\n",
-		       SOLO_MOTION_EXT_ADDR(solo_dev),
-		       SOLO_MOTION_EXT_SIZE);
-
-	out += sprintf(out, "G723: 0x%08x @ 0x%08x\n",
-		       SOLO_G723_EXT_ADDR(solo_dev),
-		       SOLO_G723_EXT_SIZE);
-
-	out += sprintf(out, "CAPT: 0x%08x @ 0x%08x (0x%08x * %d)\n",
-		       SOLO_CAP_EXT_ADDR(solo_dev),
-		       SOLO_CAP_EXT_SIZE(solo_dev),
-		       SOLO_CAP_PAGE_SIZE,
-		       SOLO_CAP_EXT_SIZE(solo_dev) / SOLO_CAP_PAGE_SIZE);
-
-	out += sprintf(out, "EREF: 0x%08x @ 0x%08x (0x%08x * %d)\n",
-		       SOLO_EREF_EXT_ADDR(solo_dev),
-		       SOLO_EREF_EXT_AREA(solo_dev),
-		       SOLO_EREF_EXT_SIZE,
-		       SOLO_EREF_EXT_AREA(solo_dev) / SOLO_EREF_EXT_SIZE);
-
-	out += sprintf(out, "MPEG: 0x%08x @ 0x%08x\n",
-		       SOLO_MP4E_EXT_ADDR(solo_dev),
-		       SOLO_MP4E_EXT_SIZE(solo_dev));
-
-	out += sprintf(out, "JPEG: 0x%08x @ 0x%08x\n",
-		       SOLO_JPEG_EXT_ADDR(solo_dev),
-		       SOLO_JPEG_EXT_SIZE(solo_dev));
-
-	return out - buf;
-}
-
-static ssize_t sdram_show(struct file *file, struct kobject *kobj,
-			  struct bin_attribute *a, char *buf,
-			  loff_t off, size_t count)
-{
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct solo_dev *solo_dev =
-		container_of(dev, struct solo_dev, dev);
-	const int size = solo_dev->sdram_size;
-
-	if (off >= size)
-		return 0;
-
-	if (off + count > size)
-		count = size - off;
-
-	if (solo_p2m_dma(solo_dev, 0, buf, off, count, 0, 0))
-		return -EIO;
-
-	return count;
-}
-
-static const struct device_attribute solo_dev_attrs[] = {
-	__ATTR(eeprom, 0640, eeprom_show, eeprom_store),
-	__ATTR(p2m_timeout, 0644, p2m_timeout_show, p2m_timeout_store),
-	__ATTR_RO(p2m_timeouts),
-	__ATTR_RO(sdram_size),
-	__ATTR_RO(tw28xx),
-	__ATTR_RO(input_map),
-	__ATTR_RO(intervals),
-	__ATTR_RO(sdram_offsets),
-};
-
-static void solo_device_release(struct device *dev)
-{
-	/* Do nothing */
-}
-
-static int solo_sysfs_init(struct solo_dev *solo_dev)
-{
-	struct bin_attribute *sdram_attr = &solo_dev->sdram_attr;
-	struct device *dev = &solo_dev->dev;
-	const char *driver;
-	int i;
-
-	if (solo_dev->type == SOLO_DEV_6110)
-		driver = "solo6110";
-	else
-		driver = "solo6010";
-
-	dev->release = solo_device_release;
-	dev->parent = &solo_dev->pdev->dev;
-	set_dev_node(dev, dev_to_node(&solo_dev->pdev->dev));
-	dev_set_name(dev, "%s-%d-%d", driver, solo_dev->vfd->num,
-		     solo_dev->nr_chans);
-
-	if (device_register(dev)) {
-		dev->parent = NULL;
-		return -ENOMEM;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(solo_dev_attrs); i++) {
-		if (device_create_file(dev, &solo_dev_attrs[i])) {
-			device_unregister(dev);
-			return -ENOMEM;
-		}
-	}
-
-	sysfs_attr_init(&sdram_attr->attr);
-	sdram_attr->attr.name = "sdram";
-	sdram_attr->attr.mode = 0440;
-	sdram_attr->read = sdram_show;
-	sdram_attr->size = solo_dev->sdram_size;
-
-	if (device_create_bin_file(dev, sdram_attr)) {
-		device_unregister(dev);
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
-static int solo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-	struct solo_dev *solo_dev;
-	int ret;
-	u8 chip_id;
-
-	solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL);
-	if (solo_dev == NULL)
-		return -ENOMEM;
-
-	if (id->driver_data == SOLO_DEV_6010)
-		dev_info(&pdev->dev, "Probing Softlogic 6010\n");
-	else
-		dev_info(&pdev->dev, "Probing Softlogic 6110\n");
-
-	solo_dev->type = id->driver_data;
-	solo_dev->pdev = pdev;
-	spin_lock_init(&solo_dev->reg_io_lock);
-	ret = v4l2_device_register(&pdev->dev, &solo_dev->v4l2_dev);
-	if (ret)
-		goto fail_probe;
-
-	/* Only for during init */
-	solo_dev->p2m_jiffies = msecs_to_jiffies(100);
-
-	ret = pci_enable_device(pdev);
-	if (ret)
-		goto fail_probe;
-
-	pci_set_master(pdev);
-
-	/* RETRY/TRDY Timeout disabled */
-	pci_write_config_byte(pdev, 0x40, 0x00);
-	pci_write_config_byte(pdev, 0x41, 0x00);
-
-	ret = pci_request_regions(pdev, SOLO6X10_NAME);
-	if (ret)
-		goto fail_probe;
-
-	solo_dev->reg_base = pci_ioremap_bar(pdev, 0);
-	if (solo_dev->reg_base == NULL) {
-		ret = -ENOMEM;
-		goto fail_probe;
-	}
-
-	chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) &
-				SOLO_CHIP_ID_MASK;
-	switch (chip_id) {
-	case 7:
-		solo_dev->nr_chans = 16;
-		solo_dev->nr_ext = 5;
-		break;
-	case 6:
-		solo_dev->nr_chans = 8;
-		solo_dev->nr_ext = 2;
-		break;
-	default:
-		dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, assuming 4 ch\n",
-			 chip_id);
-	case 5:
-		solo_dev->nr_chans = 4;
-		solo_dev->nr_ext = 1;
-	}
-
-	/* Disable all interrupts to start */
-	solo_irq_off(solo_dev, ~0);
-
-	/* Initial global settings */
-	if (solo_dev->type == SOLO_DEV_6010) {
-		solo_dev->clock_mhz = 108;
-		solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT
-			| SOLO_SYS_CFG_INPUTDIV(25)
-			| SOLO_SYS_CFG_FEEDBACKDIV(solo_dev->clock_mhz * 2 - 2)
-			| SOLO_SYS_CFG_OUTDIV(3);
-		solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config);
-	} else {
-		u32 divq, divf;
-
-		solo_dev->clock_mhz = 135;
-
-		if (solo_dev->clock_mhz < 125) {
-			divq = 3;
-			divf = (solo_dev->clock_mhz * 4) / 3 - 1;
-		} else {
-			divq = 2;
-			divf = (solo_dev->clock_mhz * 2) / 3 - 1;
-		}
-
-		solo_reg_write(solo_dev, SOLO_PLL_CONFIG,
-			       (1 << 20) | /* PLL_RANGE */
-			       (8 << 15) | /* PLL_DIVR  */
-			       (divq << 12) |
-			       (divf <<  4) |
-			       (1 <<  1)   /* PLL_FSEN */);
-
-		solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT;
-	}
-
-	solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config);
-	solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM,
-		       solo_dev->clock_mhz - 1);
-
-	/* PLL locking time of 1ms */
-	mdelay(1);
-
-	ret = request_irq(pdev->irq, solo_isr, IRQF_SHARED, SOLO6X10_NAME,
-			  solo_dev);
-	if (ret)
-		goto fail_probe;
-
-	/* Handle this from the start */
-	solo_irq_on(solo_dev, SOLO_IRQ_PCI_ERR);
-
-	ret = solo_i2c_init(solo_dev);
-	if (ret)
-		goto fail_probe;
-
-	/* Setup the DMA engine */
-	solo_reg_write(solo_dev, SOLO_DMA_CTRL,
-		       SOLO_DMA_CTRL_REFRESH_CYCLE(1) |
-		       SOLO_DMA_CTRL_SDRAM_SIZE(2) |
-		       SOLO_DMA_CTRL_SDRAM_CLK_INVERT |
-		       SOLO_DMA_CTRL_READ_CLK_SELECT |
-		       SOLO_DMA_CTRL_LATENCY(1));
-
-	/* Undocumented crap */
-	solo_reg_write(solo_dev, SOLO_DMA_CTRL1,
-		       solo_dev->type == SOLO_DEV_6010 ? 0x100 : 0x300);
-
-	if (solo_dev->type != SOLO_DEV_6010) {
-		solo_dev->usec_lsb = 0x3f;
-		solo_set_time(solo_dev);
-	}
-
-	/* Disable watchdog */
-	solo_reg_write(solo_dev, SOLO_WATCHDOG, 0);
-
-	/* Initialize sub components */
-
-	ret = solo_p2m_init(solo_dev);
-	if (ret)
-		goto fail_probe;
-
-	ret = solo_disp_init(solo_dev);
-	if (ret)
-		goto fail_probe;
-
-	ret = solo_gpio_init(solo_dev);
-	if (ret)
-		goto fail_probe;
-
-	ret = solo_tw28_init(solo_dev);
-	if (ret)
-		goto fail_probe;
-
-	ret = solo_v4l2_init(solo_dev, video_nr);
-	if (ret)
-		goto fail_probe;
-
-	ret = solo_enc_init(solo_dev);
-	if (ret)
-		goto fail_probe;
-
-	ret = solo_enc_v4l2_init(solo_dev, video_nr);
-	if (ret)
-		goto fail_probe;
-
-	ret = solo_g723_init(solo_dev);
-	if (ret)
-		goto fail_probe;
-
-	ret = solo_sysfs_init(solo_dev);
-	if (ret)
-		goto fail_probe;
-
-	/* Now that init is over, set this lower */
-	solo_dev->p2m_jiffies = msecs_to_jiffies(20);
-
-	return 0;
-
-fail_probe:
-	free_solo_dev(solo_dev);
-	return ret;
-}
-
-static void solo_pci_remove(struct pci_dev *pdev)
-{
-	struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
-	struct solo_dev *solo_dev = container_of(v4l2_dev, struct solo_dev, v4l2_dev);
-
-	free_solo_dev(solo_dev);
-}
-
-static const struct pci_device_id solo_id_table[] = {
-	/* 6010 based cards */
-	{ PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010),
-	  .driver_data = SOLO_DEV_6010 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4),
-	  .driver_data = SOLO_DEV_6010 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9),
-	  .driver_data = SOLO_DEV_6010 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16),
-	  .driver_data = SOLO_DEV_6010 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4),
-	  .driver_data = SOLO_DEV_6010 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9),
-	  .driver_data = SOLO_DEV_6010 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16),
-	  .driver_data = SOLO_DEV_6010 },
-	/* 6110 based cards */
-	{ PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6110),
-	  .driver_data = SOLO_DEV_6110 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4),
-	  .driver_data = SOLO_DEV_6110 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8),
-	  .driver_data = SOLO_DEV_6110 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16),
-	  .driver_data = SOLO_DEV_6110 },
-	{0,}
-};
-
-MODULE_DEVICE_TABLE(pci, solo_id_table);
-
-static struct pci_driver solo_pci_driver = {
-	.name = SOLO6X10_NAME,
-	.id_table = solo_id_table,
-	.probe = solo_pci_probe,
-	.remove = solo_pci_remove,
-};
-
-module_pci_driver(solo_pci_driver);
diff --git a/drivers/staging/media/solo6x10/solo6x10-disp.c b/drivers/staging/media/solo6x10/solo6x10-disp.c
deleted file mode 100644
index ed88ab4455a55..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10-disp.c
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-ioctl.h>
-
-#include "solo6x10.h"
-
-#define SOLO_VCLK_DELAY			3
-#define SOLO_PROGRESSIVE_VSIZE		1024
-
-#define SOLO_MOT_THRESH_W		64
-#define SOLO_MOT_THRESH_H		64
-#define SOLO_MOT_THRESH_SIZE		8192
-#define SOLO_MOT_THRESH_REAL		(SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H)
-#define SOLO_MOT_FLAG_SIZE		1024
-#define SOLO_MOT_FLAG_AREA		(SOLO_MOT_FLAG_SIZE * 16)
-
-static void solo_vin_config(struct solo_dev *solo_dev)
-{
-	solo_dev->vin_hstart = 8;
-	solo_dev->vin_vstart = 2;
-
-	solo_reg_write(solo_dev, SOLO_SYS_VCLK,
-		       SOLO_VCLK_SELECT(2) |
-		       SOLO_VCLK_VIN1415_DELAY(SOLO_VCLK_DELAY) |
-		       SOLO_VCLK_VIN1213_DELAY(SOLO_VCLK_DELAY) |
-		       SOLO_VCLK_VIN1011_DELAY(SOLO_VCLK_DELAY) |
-		       SOLO_VCLK_VIN0809_DELAY(SOLO_VCLK_DELAY) |
-		       SOLO_VCLK_VIN0607_DELAY(SOLO_VCLK_DELAY) |
-		       SOLO_VCLK_VIN0405_DELAY(SOLO_VCLK_DELAY) |
-		       SOLO_VCLK_VIN0203_DELAY(SOLO_VCLK_DELAY) |
-		       SOLO_VCLK_VIN0001_DELAY(SOLO_VCLK_DELAY));
-
-	solo_reg_write(solo_dev, SOLO_VI_ACT_I_P,
-		       SOLO_VI_H_START(solo_dev->vin_hstart) |
-		       SOLO_VI_V_START(solo_dev->vin_vstart) |
-		       SOLO_VI_V_STOP(solo_dev->vin_vstart +
-				      solo_dev->video_vsize));
-
-	solo_reg_write(solo_dev, SOLO_VI_ACT_I_S,
-		       SOLO_VI_H_START(solo_dev->vout_hstart) |
-		       SOLO_VI_V_START(solo_dev->vout_vstart) |
-		       SOLO_VI_V_STOP(solo_dev->vout_vstart +
-				      solo_dev->video_vsize));
-
-	solo_reg_write(solo_dev, SOLO_VI_ACT_P,
-		       SOLO_VI_H_START(0) |
-		       SOLO_VI_V_START(1) |
-		       SOLO_VI_V_STOP(SOLO_PROGRESSIVE_VSIZE));
-
-	solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT,
-		       SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0));
-
-	/* On 6110, initialize mozaic darkness stength */
-	if (solo_dev->type == SOLO_DEV_6010)
-		solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0);
-	else
-		solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 16 << 22);
-
-	solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2);
-
-	if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
-		solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
-			       SOLO_VI_PB_USER_MODE);
-		solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
-			       SOLO_VI_PB_HSIZE(858) | SOLO_VI_PB_VSIZE(246));
-		solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
-			       SOLO_VI_PB_VSTART(4) |
-			       SOLO_VI_PB_VSTOP(4 + 240));
-	} else {
-		solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
-			       SOLO_VI_PB_USER_MODE | SOLO_VI_PB_PAL);
-		solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
-			       SOLO_VI_PB_HSIZE(864) | SOLO_VI_PB_VSIZE(294));
-		solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
-			       SOLO_VI_PB_VSTART(4) |
-			       SOLO_VI_PB_VSTOP(4 + 288));
-	}
-	solo_reg_write(solo_dev, SOLO_VI_PB_ACT_H, SOLO_VI_PB_HSTART(16) |
-		       SOLO_VI_PB_HSTOP(16 + 720));
-}
-
-static void solo_vout_config_cursor(struct solo_dev *dev)
-{
-	int i;
-
-	/* Load (blank) cursor bitmap mask (2bpp) */
-	for (i = 0; i < 20; i++)
-		solo_reg_write(dev, SOLO_VO_CURSOR_MASK(i), 0);
-
-	solo_reg_write(dev, SOLO_VO_CURSOR_POS, 0);
-
-	solo_reg_write(dev, SOLO_VO_CURSOR_CLR,
-		       (0x80 << 24) | (0x80 << 16) | (0x10 << 8) | 0x80);
-	solo_reg_write(dev, SOLO_VO_CURSOR_CLR2, (0xe0 << 8) | 0x80);
-}
-
-static void solo_vout_config(struct solo_dev *solo_dev)
-{
-	solo_dev->vout_hstart = 6;
-	solo_dev->vout_vstart = 8;
-
-	solo_reg_write(solo_dev, SOLO_VO_FMT_ENC,
-		       solo_dev->video_type |
-		       SOLO_VO_USER_COLOR_SET_NAV |
-		       SOLO_VO_USER_COLOR_SET_NAH |
-		       SOLO_VO_NA_COLOR_Y(0) |
-		       SOLO_VO_NA_COLOR_CB(0) |
-		       SOLO_VO_NA_COLOR_CR(0));
-
-	solo_reg_write(solo_dev, SOLO_VO_ACT_H,
-		       SOLO_VO_H_START(solo_dev->vout_hstart) |
-		       SOLO_VO_H_STOP(solo_dev->vout_hstart +
-				      solo_dev->video_hsize));
-
-	solo_reg_write(solo_dev, SOLO_VO_ACT_V,
-		       SOLO_VO_V_START(solo_dev->vout_vstart) |
-		       SOLO_VO_V_STOP(solo_dev->vout_vstart +
-				      solo_dev->video_vsize));
-
-	solo_reg_write(solo_dev, SOLO_VO_RANGE_HV,
-		       SOLO_VO_H_LEN(solo_dev->video_hsize) |
-		       SOLO_VO_V_LEN(solo_dev->video_vsize));
-
-	/* Border & background colors */
-	solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR,
-		       (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88);
-	solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR,
-		       (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f);
-	solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR,
-		       (16 << 24) | (128 << 16) | (16 << 8) | 128);
-
-	solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
-
-	solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 0);
-
-	solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
-	solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
-
-	solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON |
-		       SOLO_VO_DISP_ERASE_COUNT(8) |
-		       SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR));
-
-
-	solo_vout_config_cursor(solo_dev);
-
-	/* Enable channels we support */
-	solo_reg_write(solo_dev, SOLO_VI_CH_ENA,
-		       (1 << solo_dev->nr_chans) - 1);
-}
-
-static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off,
-			       u16 val, int reg_size)
-{
-	u16 *buf;
-	const int n = 64, size = n * sizeof(*buf);
-	int i, ret = 0;
-
-	buf = kmalloc(size, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	for (i = 0; i < n; i++)
-		buf[i] = cpu_to_le16(val);
-
-	for (i = 0; i < reg_size; i += size) {
-		ret = solo_p2m_dma(solo_dev, 1, buf,
-				   SOLO_MOTION_EXT_ADDR(solo_dev) + off + i,
-				   size, 0, 0);
-
-		if (ret)
-			break;
-	}
-
-	kfree(buf);
-	return ret;
-}
-
-int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val)
-{
-	if (ch > solo_dev->nr_chans)
-		return -EINVAL;
-
-	return solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
-				   (ch * SOLO_MOT_THRESH_SIZE * 2),
-				   val, SOLO_MOT_THRESH_SIZE);
-}
-
-int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
-		const u16 *thresholds)
-{
-	const unsigned size = sizeof(u16) * 64;
-	u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2;
-	u16 *buf;
-	int x, y;
-	int ret = 0;
-
-	buf = kzalloc(size, GFP_KERNEL);
-	for (y = 0; y < SOLO_MOTION_SZ; y++) {
-		for (x = 0; x < SOLO_MOTION_SZ; x++)
-			buf[x] = cpu_to_le16(thresholds[y * SOLO_MOTION_SZ + x]);
-		ret |= solo_p2m_dma(solo_dev, 1, buf,
-			SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * size,
-			size, 0, 0);
-	}
-	kfree(buf);
-	return ret;
-}
-
-/* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k
- * threshold and working table for each channel. Atleast that's what the
- * spec says. However, this code (taken from rdk) has some mystery 8k
- * block right after the flag area, before the first thresh table. */
-static void solo_motion_config(struct solo_dev *solo_dev)
-{
-	int i;
-
-	for (i = 0; i < solo_dev->nr_chans; i++) {
-		/* Clear motion flag area */
-		solo_dma_vin_region(solo_dev, i * SOLO_MOT_FLAG_SIZE, 0x0000,
-				    SOLO_MOT_FLAG_SIZE);
-
-		/* Clear working cache table */
-		solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
-				    (i * SOLO_MOT_THRESH_SIZE * 2) +
-				    SOLO_MOT_THRESH_SIZE, 0x0000,
-				    SOLO_MOT_THRESH_SIZE);
-
-		/* Set default threshold table */
-		solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH);
-	}
-
-	/* Default motion settings */
-	solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) |
-		       (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
-	solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL,
-		       SOLO_VI_MOTION_FRAME_COUNT(3) |
-		       SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16)
-		       /* | SOLO_VI_MOTION_INTR_START_STOP */
-		       | SOLO_VI_MOTION_SAMPLE_COUNT(10));
-
-	solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
-	solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
-}
-
-int solo_disp_init(struct solo_dev *solo_dev)
-{
-	int i;
-
-	solo_dev->video_hsize = 704;
-	if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
-		solo_dev->video_vsize = 240;
-		solo_dev->fps = 30;
-	} else {
-		solo_dev->video_vsize = 288;
-		solo_dev->fps = 25;
-	}
-
-	solo_vin_config(solo_dev);
-	solo_motion_config(solo_dev);
-	solo_vout_config(solo_dev);
-
-	for (i = 0; i < solo_dev->nr_chans; i++)
-		solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1);
-
-	return 0;
-}
-
-void solo_disp_exit(struct solo_dev *solo_dev)
-{
-	int i;
-
-	solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0);
-	solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
-	solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
-
-	for (i = 0; i < solo_dev->nr_chans; i++) {
-		solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(i), 0);
-		solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(i), 0);
-		solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 0);
-	}
-
-	/* Set default border */
-	for (i = 0; i < 5; i++)
-		solo_reg_write(solo_dev, SOLO_VO_BORDER_X(i), 0);
-
-	for (i = 0; i < 5; i++)
-		solo_reg_write(solo_dev, SOLO_VO_BORDER_Y(i), 0);
-
-	solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_MASK, 0);
-	solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_MASK, 0);
-
-	solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0);
-	solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0);
-	solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0);
-
-	solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0);
-	solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0);
-	solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0);
-}
diff --git a/drivers/staging/media/solo6x10/solo6x10-eeprom.c b/drivers/staging/media/solo6x10/solo6x10-eeprom.c
deleted file mode 100644
index af40b3aba4100..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10-eeprom.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-
-#include "solo6x10.h"
-
-/* Control */
-#define EE_SHIFT_CLK	0x04
-#define EE_CS		0x08
-#define EE_DATA_WRITE	0x02
-#define EE_DATA_READ	0x01
-#define EE_ENB		(0x80 | EE_CS)
-
-#define eeprom_delay()	udelay(100)
-#if 0
-#define eeprom_delay()	solo_reg_read(solo_dev, SOLO_EEPROM_CTRL)
-#define eeprom_delay()	({				\
-	int i, ret;					\
-	udelay(100);					\
-	for (i = ret = 0; i < 1000 && !ret; i++)	\
-		ret = solo_eeprom_reg_read(solo_dev);	\
-})
-#endif
-#define ADDR_LEN	6
-
-/* Commands */
-#define EE_EWEN_CMD	4
-#define EE_EWDS_CMD	4
-#define EE_WRITE_CMD	5
-#define EE_READ_CMD	6
-#define EE_ERASE_CMD	7
-
-static unsigned int solo_eeprom_reg_read(struct solo_dev *solo_dev)
-{
-	return solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) & EE_DATA_READ;
-}
-
-static void solo_eeprom_reg_write(struct solo_dev *solo_dev, u32 data)
-{
-	solo_reg_write(solo_dev, SOLO_EEPROM_CTRL, data);
-	eeprom_delay();
-}
-
-static void solo_eeprom_cmd(struct solo_dev *solo_dev, int cmd)
-{
-	int i;
-
-	solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ACCESS_EN);
-	solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
-
-	for (i = 4 + ADDR_LEN; i >= 0; i--) {
-		int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0;
-
-		solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | dataval);
-		solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
-				      EE_SHIFT_CLK | dataval);
-	}
-
-	solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
-}
-
-unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en)
-{
-	int ewen_cmd = (w_en ? 0x3f : 0) | (EE_EWEN_CMD << ADDR_LEN);
-	unsigned int retval = 0;
-	int i;
-
-	solo_eeprom_cmd(solo_dev, ewen_cmd);
-
-	for (i = 0; i < 16; i++) {
-		solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
-				      EE_SHIFT_CLK);
-		retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
-		solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
-		retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
-	}
-
-	solo_eeprom_reg_write(solo_dev, ~EE_CS);
-	retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
-
-	return retval;
-}
-
-unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc)
-{
-	int read_cmd = loc | (EE_READ_CMD << ADDR_LEN);
-	unsigned short retval = 0;
-	int i;
-
-	solo_eeprom_cmd(solo_dev, read_cmd);
-
-	for (i = 0; i < 16; i++) {
-		solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
-				      EE_SHIFT_CLK);
-		retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
-		solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
-	}
-
-	solo_eeprom_reg_write(solo_dev, ~EE_CS);
-
-	return retval;
-}
-
-int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
-		      unsigned short data)
-{
-	int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN);
-	unsigned int retval;
-	int i;
-
-	solo_eeprom_cmd(solo_dev, write_cmd);
-
-	for (i = 15; i >= 0; i--) {
-		unsigned int dataval = (data >> i) & 1;
-
-		solo_eeprom_reg_write(solo_dev, EE_ENB);
-		solo_eeprom_reg_write(solo_dev,
-				      EE_ENB | (dataval << 1) | EE_SHIFT_CLK);
-	}
-
-	solo_eeprom_reg_write(solo_dev, EE_ENB);
-	solo_eeprom_reg_write(solo_dev, ~EE_CS);
-	solo_eeprom_reg_write(solo_dev, EE_ENB);
-
-	for (i = retval = 0; i < 10000 && !retval; i++)
-		retval = solo_eeprom_reg_read(solo_dev);
-
-	solo_eeprom_reg_write(solo_dev, ~EE_CS);
-
-	return !retval;
-}
diff --git a/drivers/staging/media/solo6x10/solo6x10-enc.c b/drivers/staging/media/solo6x10/solo6x10-enc.c
deleted file mode 100644
index d19c0aef5abc1..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10-enc.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/font.h>
-#include <linux/bitrev.h>
-#include <linux/slab.h>
-
-#include "solo6x10.h"
-
-#define VI_PROG_HSIZE			(1280 - 16)
-#define VI_PROG_VSIZE			(1024 - 16)
-
-#define IRQ_LEVEL			2
-
-static void solo_capture_config(struct solo_dev *solo_dev)
-{
-	unsigned long height;
-	unsigned long width;
-	void *buf;
-	int i;
-
-	solo_reg_write(solo_dev, SOLO_CAP_BASE,
-		       SOLO_CAP_MAX_PAGE((SOLO_CAP_EXT_SIZE(solo_dev)
-					  - SOLO_CAP_PAGE_SIZE) >> 16)
-		       | SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16));
-
-	/* XXX: Undocumented bits at b17 and b24 */
-	if (solo_dev->type == SOLO_DEV_6110) {
-		/* NOTE: Ref driver has (62 << 24) here as well, but it causes
-		 * wacked out frame timing on 4-port 6110. */
-		solo_reg_write(solo_dev, SOLO_CAP_BTW,
-			       (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) |
-			       SOLO_CAP_MAX_BANDWIDTH(36));
-	} else {
-		solo_reg_write(solo_dev, SOLO_CAP_BTW,
-			       (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) |
-			       SOLO_CAP_MAX_BANDWIDTH(32));
-	}
-
-	/* Set scale 1, 9 dimension */
-	width = solo_dev->video_hsize;
-	height = solo_dev->video_vsize;
-	solo_reg_write(solo_dev, SOLO_DIM_SCALE1,
-		       SOLO_DIM_H_MB_NUM(width / 16) |
-		       SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
-		       SOLO_DIM_V_MB_NUM_FIELD(height / 16));
-
-	/* Set scale 2, 10 dimension */
-	width = solo_dev->video_hsize / 2;
-	height = solo_dev->video_vsize;
-	solo_reg_write(solo_dev, SOLO_DIM_SCALE2,
-		       SOLO_DIM_H_MB_NUM(width / 16) |
-		       SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
-		       SOLO_DIM_V_MB_NUM_FIELD(height / 16));
-
-	/* Set scale 3, 11 dimension */
-	width = solo_dev->video_hsize / 2;
-	height = solo_dev->video_vsize / 2;
-	solo_reg_write(solo_dev, SOLO_DIM_SCALE3,
-		       SOLO_DIM_H_MB_NUM(width / 16) |
-		       SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
-		       SOLO_DIM_V_MB_NUM_FIELD(height / 16));
-
-	/* Set scale 4, 12 dimension */
-	width = solo_dev->video_hsize / 3;
-	height = solo_dev->video_vsize / 3;
-	solo_reg_write(solo_dev, SOLO_DIM_SCALE4,
-		       SOLO_DIM_H_MB_NUM(width / 16) |
-		       SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
-		       SOLO_DIM_V_MB_NUM_FIELD(height / 16));
-
-	/* Set scale 5, 13 dimension */
-	width = solo_dev->video_hsize / 4;
-	height = solo_dev->video_vsize / 2;
-	solo_reg_write(solo_dev, SOLO_DIM_SCALE5,
-		       SOLO_DIM_H_MB_NUM(width / 16) |
-		       SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
-		       SOLO_DIM_V_MB_NUM_FIELD(height / 16));
-
-	/* Progressive */
-	width = VI_PROG_HSIZE;
-	height = VI_PROG_VSIZE;
-	solo_reg_write(solo_dev, SOLO_DIM_PROG,
-		       SOLO_DIM_H_MB_NUM(width / 16) |
-		       SOLO_DIM_V_MB_NUM_FRAME(height / 16) |
-		       SOLO_DIM_V_MB_NUM_FIELD(height / 16));
-
-	/* Clear OSD */
-	solo_reg_write(solo_dev, SOLO_VE_OSD_CH, 0);
-	solo_reg_write(solo_dev, SOLO_VE_OSD_BASE, SOLO_EOSD_EXT_ADDR >> 16);
-	solo_reg_write(solo_dev, SOLO_VE_OSD_CLR,
-		       0xF0 << 16 | 0x80 << 8 | 0x80);
-
-	if (solo_dev->type == SOLO_DEV_6010)
-		solo_reg_write(solo_dev, SOLO_VE_OSD_OPT,
-			       SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW);
-	else
-		solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, SOLO_VE_OSD_V_DOUBLE
-			       | SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW);
-
-	/* Clear OSG buffer */
-	buf = kzalloc(SOLO_EOSD_EXT_SIZE(solo_dev), GFP_KERNEL);
-	if (!buf)
-		return;
-
-	for (i = 0; i < solo_dev->nr_chans; i++) {
-		solo_p2m_dma(solo_dev, 1, buf,
-			     SOLO_EOSD_EXT_ADDR +
-			     (SOLO_EOSD_EXT_SIZE(solo_dev) * i),
-			     SOLO_EOSD_EXT_SIZE(solo_dev), 0, 0);
-	}
-	kfree(buf);
-}
-
-#define SOLO_OSD_WRITE_SIZE (16 * OSD_TEXT_MAX)
-
-/* Should be called with enable_lock held */
-int solo_osd_print(struct solo_enc_dev *solo_enc)
-{
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-	unsigned char *str = solo_enc->osd_text;
-	u8 *buf = solo_enc->osd_buf;
-	u32 reg;
-	const struct font_desc *vga = find_font("VGA8x16");
-	const unsigned char *vga_data;
-	int i, j;
-
-	if (WARN_ON_ONCE(!vga))
-		return -ENODEV;
-
-	reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH);
-	if (!*str) {
-		/* Disable OSD on this channel */
-		reg &= ~(1 << solo_enc->ch);
-		goto out;
-	}
-
-	memset(buf, 0, SOLO_OSD_WRITE_SIZE);
-	vga_data = (const unsigned char *)vga->data;
-
-	for (i = 0; *str; i++, str++) {
-		for (j = 0; j < 16; j++) {
-			buf[(j << 1) | (i & 1) | ((i & ~1) << 4)] =
-			    bitrev8(vga_data[(*str << 4) | j]);
-		}
-	}
-
-	solo_p2m_dma(solo_dev, 1, buf,
-		     SOLO_EOSD_EXT_ADDR_CHAN(solo_dev, solo_enc->ch),
-		     SOLO_OSD_WRITE_SIZE, 0, 0);
-
-	/* Enable OSD on this channel */
-	reg |= (1 << solo_enc->ch);
-
-out:
-	solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
-	return 0;
-}
-
-/**
- * Set channel Quality Profile (0-3).
- */
-void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch,
-		    unsigned int qp)
-{
-	unsigned long flags;
-	unsigned int idx, reg;
-
-	if ((ch > 31) || (qp > 3))
-		return;
-
-	if (solo_dev->type == SOLO_DEV_6010)
-		return;
-
-	if (ch < 16) {
-		idx = 0;
-		reg = SOLO_VE_JPEG_QP_CH_L;
-	} else {
-		ch -= 16;
-		idx = 1;
-		reg = SOLO_VE_JPEG_QP_CH_H;
-	}
-	ch *= 2;
-
-	spin_lock_irqsave(&solo_dev->jpeg_qp_lock, flags);
-
-	solo_dev->jpeg_qp[idx] &= ~(3 << ch);
-	solo_dev->jpeg_qp[idx] |= (qp & 3) << ch;
-
-	solo_reg_write(solo_dev, reg, solo_dev->jpeg_qp[idx]);
-
-	spin_unlock_irqrestore(&solo_dev->jpeg_qp_lock, flags);
-}
-
-int solo_g_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch)
-{
-	int idx;
-
-	if (solo_dev->type == SOLO_DEV_6010)
-		return 2;
-
-	if (WARN_ON_ONCE(ch > 31))
-		return 2;
-
-	if (ch < 16) {
-		idx = 0;
-	} else {
-		ch -= 16;
-		idx = 1;
-	}
-	ch *= 2;
-
-	return (solo_dev->jpeg_qp[idx] >> ch) & 3;
-}
-
-#define SOLO_QP_INIT 0xaaaaaaaa
-
-static void solo_jpeg_config(struct solo_dev *solo_dev)
-{
-	if (solo_dev->type == SOLO_DEV_6010) {
-		solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL,
-			       (2 << 24) | (2 << 16) | (2 << 8) | 2);
-	} else {
-		solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL,
-			       (4 << 24) | (3 << 16) | (2 << 8) | 1);
-	}
-
-	spin_lock_init(&solo_dev->jpeg_qp_lock);
-
-	/* Initialize Quality Profile for all channels */
-	solo_dev->jpeg_qp[0] = solo_dev->jpeg_qp[1] = SOLO_QP_INIT;
-	solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, SOLO_QP_INIT);
-	solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, SOLO_QP_INIT);
-
-	solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG,
-		(SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) |
-		((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff));
-	solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff);
-	if (solo_dev->type == SOLO_DEV_6110) {
-		solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG1,
-			       (0 << 16) | (30 << 8) | 60);
-	}
-}
-
-static void solo_mp4e_config(struct solo_dev *solo_dev)
-{
-	int i;
-	u32 cfg;
-
-	solo_reg_write(solo_dev, SOLO_VE_CFG0,
-		       SOLO_VE_INTR_CTRL(IRQ_LEVEL) |
-		       SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) |
-		       SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16));
-
-
-	cfg = SOLO_VE_BYTE_ALIGN(2) | SOLO_VE_INSERT_INDEX
-		| SOLO_VE_MOTION_MODE(0);
-	if (solo_dev->type != SOLO_DEV_6010) {
-		cfg |= SOLO_VE_MPEG_SIZE_H(
-			(SOLO_MP4E_EXT_SIZE(solo_dev) >> 24) & 0x0f);
-		cfg |= SOLO_VE_JPEG_SIZE_H(
-			(SOLO_JPEG_EXT_SIZE(solo_dev) >> 24) & 0x0f);
-	}
-	solo_reg_write(solo_dev, SOLO_VE_CFG1, cfg);
-
-	solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0);
-	solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0);
-	solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0);
-	if (solo_dev->type == SOLO_DEV_6110)
-		solo_reg_write(solo_dev, SOLO_VE_WMRK_ENABLE, 0);
-	solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0);
-	solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0);
-
-	solo_reg_write(solo_dev, SOLO_VE_ATTR,
-		       SOLO_VE_LITTLE_ENDIAN |
-		       SOLO_COMP_ATTR_FCODE(1) |
-		       SOLO_COMP_TIME_INC(0) |
-		       SOLO_COMP_TIME_WIDTH(15) |
-		       SOLO_DCT_INTERVAL(solo_dev->type == SOLO_DEV_6010 ? 9 : 10));
-
-	for (i = 0; i < solo_dev->nr_chans; i++) {
-		solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i),
-			       (SOLO_EREF_EXT_ADDR(solo_dev) +
-			       (i * SOLO_EREF_EXT_SIZE)) >> 16);
-		solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE_E(i),
-			       (SOLO_EREF_EXT_ADDR(solo_dev) +
-			       ((i + 16) * SOLO_EREF_EXT_SIZE)) >> 16);
-	}
-
-	if (solo_dev->type == SOLO_DEV_6110) {
-		solo_reg_write(solo_dev, SOLO_VE_COMPT_MOT, 0x00040008);
-	} else {
-		for (i = 0; i < solo_dev->nr_chans; i++)
-			solo_reg_write(solo_dev, SOLO_VE_CH_MOT(i), 0x100);
-	}
-}
-
-int solo_enc_init(struct solo_dev *solo_dev)
-{
-	int i;
-
-	solo_capture_config(solo_dev);
-	solo_mp4e_config(solo_dev);
-	solo_jpeg_config(solo_dev);
-
-	for (i = 0; i < solo_dev->nr_chans; i++) {
-		solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
-		solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
-	}
-
-	return 0;
-}
-
-void solo_enc_exit(struct solo_dev *solo_dev)
-{
-	int i;
-
-	for (i = 0; i < solo_dev->nr_chans; i++) {
-		solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
-		solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
-	}
-}
diff --git a/drivers/staging/media/solo6x10/solo6x10-g723.c b/drivers/staging/media/solo6x10/solo6x10-g723.c
deleted file mode 100644
index c7141f2e63bdb..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10-g723.c
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/mempool.h>
-#include <linux/poll.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/control.h>
-
-#include "solo6x10.h"
-#include "solo6x10-tw28.h"
-
-#define G723_FDMA_PAGES		32
-#define G723_PERIOD_BYTES	48
-#define G723_PERIOD_BLOCK	1024
-#define G723_FRAMES_PER_PAGE	48
-
-/* Sets up channels 16-19 for decoding and 0-15 for encoding */
-#define OUTMODE_MASK		0x300
-
-#define SAMPLERATE		8000
-#define BITRATE			25
-
-/* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page
- * is broken down to 20 * 48 byte regions (one for each channel possible)
- * with the rest of the page being dummy data. */
-#define G723_MAX_BUFFER		(G723_PERIOD_BYTES * PERIODS_MAX)
-#define G723_INTR_ORDER		4 /* 0 - 4 */
-#define PERIODS_MIN		(1 << G723_INTR_ORDER)
-#define PERIODS_MAX		G723_FDMA_PAGES
-
-struct solo_snd_pcm {
-	int				on;
-	spinlock_t			lock;
-	struct solo_dev		*solo_dev;
-	unsigned char			*g723_buf;
-	dma_addr_t			g723_dma;
-};
-
-static void solo_g723_config(struct solo_dev *solo_dev)
-{
-	int clk_div;
-
-	clk_div = (solo_dev->clock_mhz * 1000000)
-		/ (SAMPLERATE * (BITRATE * 2) * 2);
-
-	solo_reg_write(solo_dev, SOLO_AUDIO_SAMPLE,
-		       SOLO_AUDIO_BITRATE(BITRATE)
-		       | SOLO_AUDIO_CLK_DIV(clk_div));
-
-	solo_reg_write(solo_dev, SOLO_AUDIO_FDMA_INTR,
-		       SOLO_AUDIO_FDMA_INTERVAL(1)
-		       | SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER)
-		       | SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16));
-
-	solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL,
-		       SOLO_AUDIO_ENABLE
-		       | SOLO_AUDIO_I2S_MODE
-		       | SOLO_AUDIO_I2S_MULTI(3)
-		       | SOLO_AUDIO_MODE(OUTMODE_MASK));
-}
-
-void solo_g723_isr(struct solo_dev *solo_dev)
-{
-	struct snd_pcm_str *pstr =
-		&solo_dev->snd_pcm->streams[SNDRV_PCM_STREAM_CAPTURE];
-	struct snd_pcm_substream *ss;
-	struct solo_snd_pcm *solo_pcm;
-
-	for (ss = pstr->substream; ss != NULL; ss = ss->next) {
-		if (snd_pcm_substream_chip(ss) == NULL)
-			continue;
-
-		/* This means open() hasn't been called on this one */
-		if (snd_pcm_substream_chip(ss) == solo_dev)
-			continue;
-
-		/* Haven't triggered a start yet */
-		solo_pcm = snd_pcm_substream_chip(ss);
-		if (!solo_pcm->on)
-			continue;
-
-		snd_pcm_period_elapsed(ss);
-	}
-}
-
-static int snd_solo_hw_params(struct snd_pcm_substream *ss,
-			      struct snd_pcm_hw_params *hw_params)
-{
-	return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
-}
-
-static int snd_solo_hw_free(struct snd_pcm_substream *ss)
-{
-	return snd_pcm_lib_free_pages(ss);
-}
-
-static const struct snd_pcm_hardware snd_solo_pcm_hw = {
-	.info			= (SNDRV_PCM_INFO_MMAP |
-				   SNDRV_PCM_INFO_INTERLEAVED |
-				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
-				   SNDRV_PCM_INFO_MMAP_VALID),
-	.formats		= SNDRV_PCM_FMTBIT_U8,
-	.rates			= SNDRV_PCM_RATE_8000,
-	.rate_min		= SAMPLERATE,
-	.rate_max		= SAMPLERATE,
-	.channels_min		= 1,
-	.channels_max		= 1,
-	.buffer_bytes_max	= G723_MAX_BUFFER,
-	.period_bytes_min	= G723_PERIOD_BYTES,
-	.period_bytes_max	= G723_PERIOD_BYTES,
-	.periods_min		= PERIODS_MIN,
-	.periods_max		= PERIODS_MAX,
-};
-
-static int snd_solo_pcm_open(struct snd_pcm_substream *ss)
-{
-	struct solo_dev *solo_dev = snd_pcm_substream_chip(ss);
-	struct solo_snd_pcm *solo_pcm;
-
-	solo_pcm = kzalloc(sizeof(*solo_pcm), GFP_KERNEL);
-	if (solo_pcm == NULL)
-		goto oom;
-
-	solo_pcm->g723_buf = pci_alloc_consistent(solo_dev->pdev,
-						  G723_PERIOD_BYTES,
-						  &solo_pcm->g723_dma);
-	if (solo_pcm->g723_buf == NULL)
-		goto oom;
-
-	spin_lock_init(&solo_pcm->lock);
-	solo_pcm->solo_dev = solo_dev;
-	ss->runtime->hw = snd_solo_pcm_hw;
-
-	snd_pcm_substream_chip(ss) = solo_pcm;
-
-	return 0;
-
-oom:
-	kfree(solo_pcm);
-	return -ENOMEM;
-}
-
-static int snd_solo_pcm_close(struct snd_pcm_substream *ss)
-{
-	struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
-
-	snd_pcm_substream_chip(ss) = solo_pcm->solo_dev;
-	pci_free_consistent(solo_pcm->solo_dev->pdev, G723_PERIOD_BYTES,
-			    solo_pcm->g723_buf, solo_pcm->g723_dma);
-	kfree(solo_pcm);
-
-	return 0;
-}
-
-static int snd_solo_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
-{
-	struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
-	struct solo_dev *solo_dev = solo_pcm->solo_dev;
-	int ret = 0;
-
-	spin_lock(&solo_pcm->lock);
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		if (solo_pcm->on == 0) {
-			/* If this is the first user, switch on interrupts */
-			if (atomic_inc_return(&solo_dev->snd_users) == 1)
-				solo_irq_on(solo_dev, SOLO_IRQ_G723);
-			solo_pcm->on = 1;
-		}
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-		if (solo_pcm->on) {
-			/* If this was our last user, switch them off */
-			if (atomic_dec_return(&solo_dev->snd_users) == 0)
-				solo_irq_off(solo_dev, SOLO_IRQ_G723);
-			solo_pcm->on = 0;
-		}
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	spin_unlock(&solo_pcm->lock);
-
-	return ret;
-}
-
-static int snd_solo_pcm_prepare(struct snd_pcm_substream *ss)
-{
-	return 0;
-}
-
-static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss)
-{
-	struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
-	struct solo_dev *solo_dev = solo_pcm->solo_dev;
-	snd_pcm_uframes_t idx = solo_reg_read(solo_dev, SOLO_AUDIO_STA) & 0x1f;
-
-	return idx * G723_FRAMES_PER_PAGE;
-}
-
-static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel,
-			     snd_pcm_uframes_t pos, void __user *dst,
-			     snd_pcm_uframes_t count)
-{
-	struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
-	struct solo_dev *solo_dev = solo_pcm->solo_dev;
-	int err, i;
-
-	for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) {
-		int page = (pos / G723_FRAMES_PER_PAGE) + i;
-
-		err = solo_p2m_dma_t(solo_dev, 0, solo_pcm->g723_dma,
-				     SOLO_G723_EXT_ADDR(solo_dev) +
-				     (page * G723_PERIOD_BLOCK) +
-				     (ss->number * G723_PERIOD_BYTES),
-				     G723_PERIOD_BYTES, 0, 0);
-		if (err)
-			return err;
-
-		err = copy_to_user(dst + (i * G723_PERIOD_BYTES),
-				   solo_pcm->g723_buf, G723_PERIOD_BYTES);
-
-		if (err)
-			return -EFAULT;
-	}
-
-	return 0;
-}
-
-static struct snd_pcm_ops snd_solo_pcm_ops = {
-	.open = snd_solo_pcm_open,
-	.close = snd_solo_pcm_close,
-	.ioctl = snd_pcm_lib_ioctl,
-	.hw_params = snd_solo_hw_params,
-	.hw_free = snd_solo_hw_free,
-	.prepare = snd_solo_pcm_prepare,
-	.trigger = snd_solo_pcm_trigger,
-	.pointer = snd_solo_pcm_pointer,
-	.copy = snd_solo_pcm_copy,
-};
-
-static int snd_solo_capture_volume_info(struct snd_kcontrol *kcontrol,
-					struct snd_ctl_elem_info *info)
-{
-	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	info->count = 1;
-	info->value.integer.min = 0;
-	info->value.integer.max = 15;
-	info->value.integer.step = 1;
-
-	return 0;
-}
-
-static int snd_solo_capture_volume_get(struct snd_kcontrol *kcontrol,
-				       struct snd_ctl_elem_value *value)
-{
-	struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol);
-	u8 ch = value->id.numid - 1;
-
-	value->value.integer.value[0] = tw28_get_audio_gain(solo_dev, ch);
-
-	return 0;
-}
-
-static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol,
-				       struct snd_ctl_elem_value *value)
-{
-	struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol);
-	u8 ch = value->id.numid - 1;
-	u8 old_val;
-
-	old_val = tw28_get_audio_gain(solo_dev, ch);
-	if (old_val == value->value.integer.value[0])
-		return 0;
-
-	tw28_set_audio_gain(solo_dev, ch, value->value.integer.value[0]);
-
-	return 1;
-}
-
-static struct snd_kcontrol_new snd_solo_capture_volume = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "Capture Volume",
-	.info = snd_solo_capture_volume_info,
-	.get = snd_solo_capture_volume_get,
-	.put = snd_solo_capture_volume_put,
-};
-
-static int solo_snd_pcm_init(struct solo_dev *solo_dev)
-{
-	struct snd_card *card = solo_dev->snd_card;
-	struct snd_pcm *pcm;
-	struct snd_pcm_substream *ss;
-	int ret;
-	int i;
-
-	ret = snd_pcm_new(card, card->driver, 0, 0, solo_dev->nr_chans,
-			  &pcm);
-	if (ret < 0)
-		return ret;
-
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-			&snd_solo_pcm_ops);
-
-	snd_pcm_chip(pcm) = solo_dev;
-	pcm->info_flags = 0;
-	strcpy(pcm->name, card->shortname);
-
-	for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
-	     ss; ss = ss->next, i++)
-		sprintf(ss->name, "Camera #%d Audio", i);
-
-	ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
-					SNDRV_DMA_TYPE_CONTINUOUS,
-					snd_dma_continuous_data(GFP_KERNEL),
-					G723_MAX_BUFFER, G723_MAX_BUFFER);
-	if (ret < 0)
-		return ret;
-
-	solo_dev->snd_pcm = pcm;
-
-	return 0;
-}
-
-int solo_g723_init(struct solo_dev *solo_dev)
-{
-	static struct snd_device_ops ops = { NULL };
-	struct snd_card *card;
-	struct snd_kcontrol_new kctl;
-	char name[32];
-	int ret;
-
-	atomic_set(&solo_dev->snd_users, 0);
-
-	/* Allows for easier mapping between video and audio */
-	sprintf(name, "Softlogic%d", solo_dev->vfd->num);
-
-	ret = snd_card_new(&solo_dev->pdev->dev,
-			   SNDRV_DEFAULT_IDX1, name, THIS_MODULE, 0,
-			   &solo_dev->snd_card);
-	if (ret < 0)
-		return ret;
-
-	card = solo_dev->snd_card;
-
-	strcpy(card->driver, SOLO6X10_NAME);
-	strcpy(card->shortname, "SOLO-6x10 Audio");
-	sprintf(card->longname, "%s on %s IRQ %d", card->shortname,
-		pci_name(solo_dev->pdev), solo_dev->pdev->irq);
-
-	ret = snd_device_new(card, SNDRV_DEV_LOWLEVEL, solo_dev, &ops);
-	if (ret < 0)
-		goto snd_error;
-
-	/* Mixer controls */
-	strcpy(card->mixername, "SOLO-6x10");
-	kctl = snd_solo_capture_volume;
-	kctl.count = solo_dev->nr_chans;
-
-	ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev));
-	if (ret < 0)
-		return ret;
-
-	ret = solo_snd_pcm_init(solo_dev);
-	if (ret < 0)
-		goto snd_error;
-
-	ret = snd_card_register(card);
-	if (ret < 0)
-		goto snd_error;
-
-	solo_g723_config(solo_dev);
-
-	dev_info(&solo_dev->pdev->dev, "Alsa sound card as %s\n", name);
-
-	return 0;
-
-snd_error:
-	snd_card_free(card);
-	return ret;
-}
-
-void solo_g723_exit(struct solo_dev *solo_dev)
-{
-	if (!solo_dev->snd_card)
-		return;
-
-	solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, 0);
-	solo_irq_off(solo_dev, SOLO_IRQ_G723);
-
-	snd_card_free(solo_dev->snd_card);
-	solo_dev->snd_card = NULL;
-}
diff --git a/drivers/staging/media/solo6x10/solo6x10-gpio.c b/drivers/staging/media/solo6x10/solo6x10-gpio.c
deleted file mode 100644
index 6d3b4a36bc119..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10-gpio.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/uaccess.h>
-
-#include "solo6x10.h"
-
-static void solo_gpio_mode(struct solo_dev *solo_dev,
-			   unsigned int port_mask, unsigned int mode)
-{
-	int port;
-	unsigned int ret;
-
-	ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0);
-
-	/* To set gpio */
-	for (port = 0; port < 16; port++) {
-		if (!((1 << port) & port_mask))
-			continue;
-
-		ret &= (~(3 << (port << 1)));
-		ret |= ((mode & 3) << (port << 1));
-	}
-
-	solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_0, ret);
-
-	/* To set extended gpio - sensor */
-	ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1);
-
-	for (port = 0; port < 16; port++) {
-		if (!((1 << (port + 16)) & port_mask))
-			continue;
-
-		if (!mode)
-			ret &= ~(1 << port);
-		else
-			ret |= 1 << port;
-	}
-
-	solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret);
-}
-
-static void solo_gpio_set(struct solo_dev *solo_dev, unsigned int value)
-{
-	solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
-		       solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) | value);
-}
-
-static void solo_gpio_clear(struct solo_dev *solo_dev, unsigned int value)
-{
-	solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
-		       solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) & ~value);
-}
-
-static void solo_gpio_config(struct solo_dev *solo_dev)
-{
-	/* Video reset */
-	solo_gpio_mode(solo_dev, 0x30, 1);
-	solo_gpio_clear(solo_dev, 0x30);
-	udelay(100);
-	solo_gpio_set(solo_dev, 0x30);
-	udelay(100);
-
-	/* Warning: Don't touch the next line unless you're sure of what
-	 * you're doing: first four gpio [0-3] are used for video. */
-	solo_gpio_mode(solo_dev, 0x0f, 2);
-
-	/* We use bit 8-15 of SOLO_GPIO_CONFIG_0 for relay purposes */
-	solo_gpio_mode(solo_dev, 0xff00, 1);
-
-	/* Initially set relay status to 0 */
-	solo_gpio_clear(solo_dev, 0xff00);
-}
-
-int solo_gpio_init(struct solo_dev *solo_dev)
-{
-	solo_gpio_config(solo_dev);
-	return 0;
-}
-
-void solo_gpio_exit(struct solo_dev *solo_dev)
-{
-	solo_gpio_clear(solo_dev, 0x30);
-	solo_gpio_config(solo_dev);
-}
diff --git a/drivers/staging/media/solo6x10/solo6x10-i2c.c b/drivers/staging/media/solo6x10/solo6x10-i2c.c
deleted file mode 100644
index c908672b2c401..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10-i2c.c
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-/* XXX: The SOLO6x10 i2c does not have separate interrupts for each i2c
- * channel. The bus can only handle one i2c event at a time. The below handles
- * this all wrong. We should be using the status registers to see if the bus
- * is in use, and have a global lock to check the status register. Also,
- * the bulk of the work should be handled out-of-interrupt. The ugly loops
- * that occur during interrupt scare me. The ISR should merely signal
- * thread context, ACK the interrupt, and move on. -- BenC */
-
-#include <linux/kernel.h>
-
-#include "solo6x10.h"
-
-u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off)
-{
-	struct i2c_msg msgs[2];
-	u8 data;
-
-	msgs[0].flags = 0;
-	msgs[0].addr = addr;
-	msgs[0].len = 1;
-	msgs[0].buf = &off;
-
-	msgs[1].flags = I2C_M_RD;
-	msgs[1].addr = addr;
-	msgs[1].len = 1;
-	msgs[1].buf = &data;
-
-	i2c_transfer(&solo_dev->i2c_adap[id], msgs, 2);
-
-	return data;
-}
-
-void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr,
-			u8 off, u8 data)
-{
-	struct i2c_msg msgs;
-	u8 buf[2];
-
-	buf[0] = off;
-	buf[1] = data;
-	msgs.flags = 0;
-	msgs.addr = addr;
-	msgs.len = 2;
-	msgs.buf = buf;
-
-	i2c_transfer(&solo_dev->i2c_adap[id], &msgs, 1);
-}
-
-static void solo_i2c_flush(struct solo_dev *solo_dev, int wr)
-{
-	u32 ctrl;
-
-	ctrl = SOLO_IIC_CH_SET(solo_dev->i2c_id);
-
-	if (solo_dev->i2c_state == IIC_STATE_START)
-		ctrl |= SOLO_IIC_START;
-
-	if (wr) {
-		ctrl |= SOLO_IIC_WRITE;
-	} else {
-		ctrl |= SOLO_IIC_READ;
-		if (!(solo_dev->i2c_msg->flags & I2C_M_NO_RD_ACK))
-			ctrl |= SOLO_IIC_ACK_EN;
-	}
-
-	if (solo_dev->i2c_msg_ptr == solo_dev->i2c_msg->len)
-		ctrl |= SOLO_IIC_STOP;
-
-	solo_reg_write(solo_dev, SOLO_IIC_CTRL, ctrl);
-}
-
-static void solo_i2c_start(struct solo_dev *solo_dev)
-{
-	u32 addr = solo_dev->i2c_msg->addr << 1;
-
-	if (solo_dev->i2c_msg->flags & I2C_M_RD)
-		addr |= 1;
-
-	solo_dev->i2c_state = IIC_STATE_START;
-	solo_reg_write(solo_dev, SOLO_IIC_TXD, addr);
-	solo_i2c_flush(solo_dev, 1);
-}
-
-static void solo_i2c_stop(struct solo_dev *solo_dev)
-{
-	solo_irq_off(solo_dev, SOLO_IRQ_IIC);
-	solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
-	solo_dev->i2c_state = IIC_STATE_STOP;
-	wake_up(&solo_dev->i2c_wait);
-}
-
-static int solo_i2c_handle_read(struct solo_dev *solo_dev)
-{
-prepare_read:
-	if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
-		solo_i2c_flush(solo_dev, 0);
-		return 0;
-	}
-
-	solo_dev->i2c_msg_ptr = 0;
-	solo_dev->i2c_msg++;
-	solo_dev->i2c_msg_num--;
-
-	if (solo_dev->i2c_msg_num == 0) {
-		solo_i2c_stop(solo_dev);
-		return 0;
-	}
-
-	if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
-		solo_i2c_start(solo_dev);
-	} else {
-		if (solo_dev->i2c_msg->flags & I2C_M_RD)
-			goto prepare_read;
-		else
-			solo_i2c_stop(solo_dev);
-	}
-
-	return 0;
-}
-
-static int solo_i2c_handle_write(struct solo_dev *solo_dev)
-{
-retry_write:
-	if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
-		solo_reg_write(solo_dev, SOLO_IIC_TXD,
-			       solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr]);
-		solo_dev->i2c_msg_ptr++;
-		solo_i2c_flush(solo_dev, 1);
-		return 0;
-	}
-
-	solo_dev->i2c_msg_ptr = 0;
-	solo_dev->i2c_msg++;
-	solo_dev->i2c_msg_num--;
-
-	if (solo_dev->i2c_msg_num == 0) {
-		solo_i2c_stop(solo_dev);
-		return 0;
-	}
-
-	if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
-		solo_i2c_start(solo_dev);
-	} else {
-		if (solo_dev->i2c_msg->flags & I2C_M_RD)
-			solo_i2c_stop(solo_dev);
-		else
-			goto retry_write;
-	}
-
-	return 0;
-}
-
-int solo_i2c_isr(struct solo_dev *solo_dev)
-{
-	u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL);
-	int ret = -EINVAL;
-
-
-	if (CHK_FLAGS(status, SOLO_IIC_STATE_TRNS | SOLO_IIC_STATE_SIG_ERR)
-	    || solo_dev->i2c_id < 0) {
-		solo_i2c_stop(solo_dev);
-		return -ENXIO;
-	}
-
-	switch (solo_dev->i2c_state) {
-	case IIC_STATE_START:
-		if (solo_dev->i2c_msg->flags & I2C_M_RD) {
-			solo_dev->i2c_state = IIC_STATE_READ;
-			ret = solo_i2c_handle_read(solo_dev);
-			break;
-		}
-
-		solo_dev->i2c_state = IIC_STATE_WRITE;
-	case IIC_STATE_WRITE:
-		ret = solo_i2c_handle_write(solo_dev);
-		break;
-
-	case IIC_STATE_READ:
-		solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr] =
-			solo_reg_read(solo_dev, SOLO_IIC_RXD);
-		solo_dev->i2c_msg_ptr++;
-
-		ret = solo_i2c_handle_read(solo_dev);
-		break;
-
-	default:
-		solo_i2c_stop(solo_dev);
-	}
-
-	return ret;
-}
-
-static int solo_i2c_master_xfer(struct i2c_adapter *adap,
-				struct i2c_msg msgs[], int num)
-{
-	struct solo_dev *solo_dev = adap->algo_data;
-	unsigned long timeout;
-	int ret;
-	int i;
-	DEFINE_WAIT(wait);
-
-	for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
-		if (&solo_dev->i2c_adap[i] == adap)
-			break;
-	}
-
-	if (i == SOLO_I2C_ADAPTERS)
-		return num; /* XXX Right return value for failure? */
-
-	mutex_lock(&solo_dev->i2c_mutex);
-	solo_dev->i2c_id = i;
-	solo_dev->i2c_msg = msgs;
-	solo_dev->i2c_msg_num = num;
-	solo_dev->i2c_msg_ptr = 0;
-
-	solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
-	solo_irq_on(solo_dev, SOLO_IRQ_IIC);
-	solo_i2c_start(solo_dev);
-
-	timeout = HZ / 2;
-
-	for (;;) {
-		prepare_to_wait(&solo_dev->i2c_wait, &wait,
-				TASK_INTERRUPTIBLE);
-
-		if (solo_dev->i2c_state == IIC_STATE_STOP)
-			break;
-
-		timeout = schedule_timeout(timeout);
-		if (!timeout)
-			break;
-
-		if (signal_pending(current))
-			break;
-	}
-
-	finish_wait(&solo_dev->i2c_wait, &wait);
-	ret = num - solo_dev->i2c_msg_num;
-	solo_dev->i2c_state = IIC_STATE_IDLE;
-	solo_dev->i2c_id = -1;
-
-	mutex_unlock(&solo_dev->i2c_mutex);
-
-	return ret;
-}
-
-static u32 solo_i2c_functionality(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_I2C;
-}
-
-static const struct i2c_algorithm solo_i2c_algo = {
-	.master_xfer	= solo_i2c_master_xfer,
-	.functionality	= solo_i2c_functionality,
-};
-
-int solo_i2c_init(struct solo_dev *solo_dev)
-{
-	int i;
-	int ret;
-
-	solo_reg_write(solo_dev, SOLO_IIC_CFG,
-		       SOLO_IIC_PRESCALE(8) | SOLO_IIC_ENABLE);
-
-	solo_dev->i2c_id = -1;
-	solo_dev->i2c_state = IIC_STATE_IDLE;
-	init_waitqueue_head(&solo_dev->i2c_wait);
-	mutex_init(&solo_dev->i2c_mutex);
-
-	for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
-		struct i2c_adapter *adap = &solo_dev->i2c_adap[i];
-
-		snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d",
-			 SOLO6X10_NAME, i);
-		adap->algo = &solo_i2c_algo;
-		adap->algo_data = solo_dev;
-		adap->retries = 1;
-		adap->dev.parent = &solo_dev->pdev->dev;
-
-		ret = i2c_add_adapter(adap);
-		if (ret) {
-			adap->algo_data = NULL;
-			break;
-		}
-	}
-
-	if (ret) {
-		for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
-			if (!solo_dev->i2c_adap[i].algo_data)
-				break;
-			i2c_del_adapter(&solo_dev->i2c_adap[i]);
-			solo_dev->i2c_adap[i].algo_data = NULL;
-		}
-		return ret;
-	}
-
-	return 0;
-}
-
-void solo_i2c_exit(struct solo_dev *solo_dev)
-{
-	int i;
-
-	for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
-		if (!solo_dev->i2c_adap[i].algo_data)
-			continue;
-		i2c_del_adapter(&solo_dev->i2c_adap[i]);
-		solo_dev->i2c_adap[i].algo_data = NULL;
-	}
-}
diff --git a/drivers/staging/media/solo6x10/solo6x10-jpeg.h b/drivers/staging/media/solo6x10/solo6x10-jpeg.h
deleted file mode 100644
index 1c66a46da514f..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10-jpeg.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-#ifndef __SOLO6X10_JPEG_H
-#define __SOLO6X10_JPEG_H
-
-static const unsigned char jpeg_header[] = {
-	0xff, 0xd8, 0xff, 0xfe, 0x00, 0x0d, 0x42, 0x6c,
-	0x75, 0x65, 0x63, 0x68, 0x65, 0x72, 0x72, 0x79,
-	0x20, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x20, 0x16,
-	0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, 0x1a, 0x1c,
-	0x24, 0x22, 0x20, 0x26, 0x30, 0x50, 0x34, 0x30,
-	0x2c, 0x2c, 0x30, 0x62, 0x46, 0x4a, 0x3a, 0x50,
-	0x74, 0x66, 0x7a, 0x78, 0x72, 0x66, 0x70, 0x6e,
-	0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, 0xae, 0x8a,
-	0x6e, 0x70, 0xa0, 0xda, 0xa2, 0xae, 0xbe, 0xc4,
-	0xce, 0xd0, 0xce, 0x7c, 0x9a, 0xe2, 0xf2, 0xe0,
-	0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, 0xff, 0xdb,
-	0x00, 0x43, 0x01, 0x22, 0x24, 0x24, 0x30, 0x2a,
-	0x30, 0x5e, 0x34, 0x34, 0x5e, 0xc6, 0x84, 0x70,
-	0x84, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-	0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-	0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-	0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-	0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-	0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-	0xc6, 0xc6, 0xc6, 0xff, 0xc4, 0x01, 0xa2, 0x00,
-	0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
-	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01,
-	0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
-	0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03,
-	0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41,
-	0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14,
-	0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1,
-	0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62,
-	0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19,
-	0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34,
-	0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
-	0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
-	0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
-	0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74,
-	0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84,
-	0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
-	0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2,
-	0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
-	0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
-	0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
-	0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
-	0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5,
-	0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
-	0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01,
-	0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-	0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	0x08, 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01,
-	0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
-	0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02,
-	0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12,
-	0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32,
-	0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1,
-	0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72,
-	0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1,
-	0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29,
-	0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43,
-	0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53,
-	0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63,
-	0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73,
-	0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82,
-	0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
-	0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
-	0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
-	0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
-	0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
-	0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5,
-	0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4,
-	0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3,
-	0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff,
-	0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x02, 0xc0,
-	0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03,
-	0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01,
-	0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
-};
-
-/* This is the byte marker for the start of SOF0: 0xffc0 marker */
-#define SOF0_START	575
-
-/* This is the byte marker for the start of the DQT */
-#define DQT_START	17
-#define DQT_LEN		138
-static const unsigned char jpeg_dqt[4][DQT_LEN] = {
-	{
-		0xff, 0xdb, 0x00, 0x43, 0x00,
-		0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07,
-		0x07, 0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14,
-		0x0d, 0x0c, 0x0b, 0x0b, 0x0c, 0x19, 0x12, 0x13,
-		0x0f, 0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a,
-		0x1c, 0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22,
-		0x2c, 0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c,
-		0x30, 0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, 0x39,
-		0x3d, 0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32,
-		0xff, 0xdb, 0x00, 0x43, 0x01,
-		0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0d,
-		0x0d, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, 0x32,
-		0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
-		0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
-		0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
-		0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
-		0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
-		0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32
-	}, {
-		0xff, 0xdb, 0x00, 0x43, 0x00,
-		0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e,
-		0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
-		0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
-		0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33,
-		0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44,
-		0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57,
-		0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
-		0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
-		0xff, 0xdb, 0x00, 0x43, 0x01,
-		0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
-		0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
-		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-		0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
-	}, {
-		0xff, 0xdb, 0x00, 0x43, 0x00,
-		0x20, 0x16, 0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c,
-		0x1a, 0x1c, 0x24, 0x22, 0x20, 0x26, 0x30, 0x50,
-		0x34, 0x30, 0x2c, 0x2c, 0x30, 0x62, 0x46, 0x4a,
-		0x3a, 0x50, 0x74, 0x66, 0x7a, 0x78, 0x72, 0x66,
-		0x70, 0x6e, 0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88,
-		0xae, 0x8a, 0x6e, 0x70, 0xa0, 0xda, 0xa2, 0xae,
-		0xbe, 0xc4, 0xce, 0xd0, 0xce, 0x7c, 0x9a, 0xe2,
-		0xf2, 0xe0, 0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6,
-		0xff, 0xdb, 0x00, 0x43, 0x01,
-		0x22, 0x24, 0x24, 0x30, 0x2a, 0x30, 0x5e, 0x34,
-		0x34, 0x5e, 0xc6, 0x84, 0x70, 0x84, 0xc6, 0xc6,
-		0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-		0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-		0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-		0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-		0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-		0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6
-	}, {
-		0xff, 0xdb, 0x00, 0x43, 0x00,
-		0x30, 0x21, 0x24, 0x2a, 0x24, 0x1e, 0x30, 0x2a,
-		0x27, 0x2a, 0x36, 0x33, 0x30, 0x39, 0x48, 0x78,
-		0x4e, 0x48, 0x42, 0x42, 0x48, 0x93, 0x69, 0x6f,
-		0x57, 0x78, 0xae, 0x99, 0xb7, 0xb4, 0xab, 0x99,
-		0xa8, 0xa5, 0xc0, 0xd8, 0xff, 0xea, 0xc0, 0xcc,
-		0xff, 0xcf, 0xa5, 0xa8, 0xf0, 0xff, 0xf3, 0xff,
-		0xff, 0xff, 0xff, 0xff, 0xff, 0xba, 0xe7, 0xff,
-		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-		0xff, 0xdb, 0x00, 0x43, 0x01,
-		0x33, 0x36, 0x36, 0x48, 0x3f, 0x48, 0x8d, 0x4e,
-		0x4e, 0x8d, 0xff, 0xc6, 0xa8, 0xc6, 0xff, 0xff,
-		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-	}
-};
-
-#endif /* __SOLO6X10_JPEG_H */
diff --git a/drivers/staging/media/solo6x10/solo6x10-offsets.h b/drivers/staging/media/solo6x10/solo6x10-offsets.h
deleted file mode 100644
index d6aea7c2a6769..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10-offsets.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-#ifndef __SOLO6X10_OFFSETS_H
-#define __SOLO6X10_OFFSETS_H
-
-#define SOLO_DISP_EXT_ADDR			0x00000000
-#define SOLO_DISP_EXT_SIZE			0x00480000
-
-#define SOLO_EOSD_EXT_ADDR \
-	(SOLO_DISP_EXT_ADDR + SOLO_DISP_EXT_SIZE)
-#define SOLO_EOSD_EXT_SIZE(__solo) \
-	(__solo->type == SOLO_DEV_6010 ? 0x10000 : 0x20000)
-#define SOLO_EOSD_EXT_SIZE_MAX			0x20000
-#define SOLO_EOSD_EXT_AREA(__solo) \
-	(SOLO_EOSD_EXT_SIZE(__solo) * 32)
-#define SOLO_EOSD_EXT_ADDR_CHAN(__solo, ch) \
-	(SOLO_EOSD_EXT_ADDR + SOLO_EOSD_EXT_SIZE(__solo) * (ch))
-
-#define SOLO_MOTION_EXT_ADDR(__solo) \
-	(SOLO_EOSD_EXT_ADDR + SOLO_EOSD_EXT_AREA(__solo))
-#define SOLO_MOTION_EXT_SIZE			0x00080000
-
-#define SOLO_G723_EXT_ADDR(__solo) \
-	(SOLO_MOTION_EXT_ADDR(__solo) + SOLO_MOTION_EXT_SIZE)
-#define SOLO_G723_EXT_SIZE			0x00010000
-
-#define SOLO_CAP_EXT_ADDR(__solo) \
-	(SOLO_G723_EXT_ADDR(__solo) + SOLO_G723_EXT_SIZE)
-
-/* 18 is the maximum number of pages required for PAL@D1, the largest frame
- * possible */
-#define SOLO_CAP_PAGE_SIZE			(18 << 16)
-
-/* Always allow the encoder enough for 16 channels, even if we have less. The
- * exception is if we have card with only 32Megs of memory. */
-#define SOLO_CAP_EXT_SIZE(__solo) \
-	((((__solo->sdram_size <= (32 << 20)) ? 4 : 16) + 1)	\
-	 * SOLO_CAP_PAGE_SIZE)
-
-#define SOLO_EREF_EXT_ADDR(__solo) \
-	(SOLO_CAP_EXT_ADDR(__solo) + SOLO_CAP_EXT_SIZE(__solo))
-#define SOLO_EREF_EXT_SIZE			0x00140000
-#define SOLO_EREF_EXT_AREA(__solo) \
-	(SOLO_EREF_EXT_SIZE * __solo->nr_chans * 2)
-
-#define __SOLO_JPEG_MIN_SIZE(__solo)		(__solo->nr_chans * 0x00080000)
-
-#define SOLO_MP4E_EXT_ADDR(__solo) \
-	(SOLO_EREF_EXT_ADDR(__solo) + SOLO_EREF_EXT_AREA(__solo))
-#define SOLO_MP4E_EXT_SIZE(__solo) \
-	max((__solo->nr_chans * 0x00080000),				\
-	    min(((__solo->sdram_size - SOLO_MP4E_EXT_ADDR(__solo)) -	\
-		 __SOLO_JPEG_MIN_SIZE(__solo)), 0x00ff0000))
-
-#define __SOLO_JPEG_MIN_SIZE(__solo)		(__solo->nr_chans * 0x00080000)
-#define SOLO_JPEG_EXT_ADDR(__solo) \
-		(SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo))
-#define SOLO_JPEG_EXT_SIZE(__solo) \
-	max(__SOLO_JPEG_MIN_SIZE(__solo),				\
-	    min((__solo->sdram_size - SOLO_JPEG_EXT_ADDR(__solo)), 0x00ff0000))
-
-#define SOLO_SDRAM_END(__solo) \
-	(SOLO_JPEG_EXT_ADDR(__solo) + SOLO_JPEG_EXT_SIZE(__solo))
-
-#endif /* __SOLO6X10_OFFSETS_H */
diff --git a/drivers/staging/media/solo6x10/solo6x10-p2m.c b/drivers/staging/media/solo6x10/solo6x10-p2m.c
deleted file mode 100644
index 8c8484674d2f6..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10-p2m.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include "solo6x10.h"
-
-static int multi_p2m;
-module_param(multi_p2m, uint, 0644);
-MODULE_PARM_DESC(multi_p2m,
-		 "Use multiple P2M DMA channels (default: no, 6010-only)");
-
-static int desc_mode;
-module_param(desc_mode, uint, 0644);
-MODULE_PARM_DESC(desc_mode,
-		 "Allow use of descriptor mode DMA (default: no, 6010-only)");
-
-int solo_p2m_dma(struct solo_dev *solo_dev, int wr,
-		 void *sys_addr, u32 ext_addr, u32 size,
-		 int repeat, u32 ext_size)
-{
-	dma_addr_t dma_addr;
-	int ret;
-
-	if (WARN_ON_ONCE((unsigned long)sys_addr & 0x03))
-		return -EINVAL;
-	if (WARN_ON_ONCE(!size))
-		return -EINVAL;
-
-	dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size,
-				  wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-	if (pci_dma_mapping_error(solo_dev->pdev, dma_addr))
-		return -ENOMEM;
-
-	ret = solo_p2m_dma_t(solo_dev, wr, dma_addr, ext_addr, size,
-			     repeat, ext_size);
-
-	pci_unmap_single(solo_dev->pdev, dma_addr, size,
-			 wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-
-	return ret;
-}
-
-/* Mutex must be held for p2m_id before calling this!! */
-int solo_p2m_dma_desc(struct solo_dev *solo_dev,
-		      struct solo_p2m_desc *desc, dma_addr_t desc_dma,
-		      int desc_cnt)
-{
-	struct solo_p2m_dev *p2m_dev;
-	unsigned int timeout;
-	unsigned int config = 0;
-	int ret = 0;
-	int p2m_id = 0;
-
-	/* Get next ID. According to Softlogic, 6110 has problems on !=0 P2M */
-	if (solo_dev->type != SOLO_DEV_6110 && multi_p2m) {
-		p2m_id = atomic_inc_return(&solo_dev->p2m_count) % SOLO_NR_P2M;
-		if (p2m_id < 0)
-			p2m_id = -p2m_id;
-	}
-
-	p2m_dev = &solo_dev->p2m_dev[p2m_id];
-
-	if (mutex_lock_interruptible(&p2m_dev->mutex))
-		return -EINTR;
-
-	reinit_completion(&p2m_dev->completion);
-	p2m_dev->error = 0;
-
-	if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && desc_mode) {
-		/* For 6010 with more than one desc, we can do a one-shot */
-		p2m_dev->desc_count = p2m_dev->desc_idx = 0;
-		config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(p2m_id));
-
-		solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(p2m_id), desc_dma);
-		solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(p2m_id), desc_cnt);
-		solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config |
-			       SOLO_P2M_DESC_MODE);
-	} else {
-		/* For single descriptors and 6110, we need to run each desc */
-		p2m_dev->desc_count = desc_cnt;
-		p2m_dev->desc_idx = 1;
-		p2m_dev->descs = desc;
-
-		solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(p2m_id),
-			       desc[1].dma_addr);
-		solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(p2m_id),
-			       desc[1].ext_addr);
-		solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(p2m_id),
-			       desc[1].cfg);
-		solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id),
-			       desc[1].ctrl);
-	}
-
-	timeout = wait_for_completion_timeout(&p2m_dev->completion,
-					      solo_dev->p2m_jiffies);
-
-	if (WARN_ON_ONCE(p2m_dev->error))
-		ret = -EIO;
-	else if (timeout == 0) {
-		solo_dev->p2m_timeouts++;
-		ret = -EAGAIN;
-	}
-
-	solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), 0);
-
-	/* Don't write here for the no_desc_mode case, because config is 0.
-	 * We can't test no_desc_mode again, it might race. */
-	if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && config)
-		solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config);
-
-	mutex_unlock(&p2m_dev->mutex);
-
-	return ret;
-}
-
-void solo_p2m_fill_desc(struct solo_p2m_desc *desc, int wr,
-			dma_addr_t dma_addr, u32 ext_addr, u32 size,
-			int repeat, u32 ext_size)
-{
-	WARN_ON_ONCE(dma_addr & 0x03);
-	WARN_ON_ONCE(!size);
-
-	desc->cfg = SOLO_P2M_COPY_SIZE(size >> 2);
-	desc->ctrl = SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) |
-		(wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON;
-
-	if (repeat) {
-		desc->cfg |= SOLO_P2M_EXT_INC(ext_size >> 2);
-		desc->ctrl |=  SOLO_P2M_PCI_INC(size >> 2) |
-			 SOLO_P2M_REPEAT(repeat);
-	}
-
-	desc->dma_addr = dma_addr;
-	desc->ext_addr = ext_addr;
-}
-
-int solo_p2m_dma_t(struct solo_dev *solo_dev, int wr,
-		   dma_addr_t dma_addr, u32 ext_addr, u32 size,
-		   int repeat, u32 ext_size)
-{
-	struct solo_p2m_desc desc[2];
-
-	solo_p2m_fill_desc(&desc[1], wr, dma_addr, ext_addr, size, repeat,
-			   ext_size);
-
-	/* No need for desc_dma since we know it is a single-shot */
-	return solo_p2m_dma_desc(solo_dev, desc, 0, 1);
-}
-
-void solo_p2m_isr(struct solo_dev *solo_dev, int id)
-{
-	struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id];
-	struct solo_p2m_desc *desc;
-
-	if (p2m_dev->desc_count <= p2m_dev->desc_idx) {
-		complete(&p2m_dev->completion);
-		return;
-	}
-
-	/* Setup next descriptor */
-	p2m_dev->desc_idx++;
-	desc = &p2m_dev->descs[p2m_dev->desc_idx];
-
-	solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
-	solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), desc->dma_addr);
-	solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), desc->ext_addr);
-	solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id), desc->cfg);
-	solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), desc->ctrl);
-}
-
-void solo_p2m_error_isr(struct solo_dev *solo_dev)
-{
-	unsigned int err = solo_reg_read(solo_dev, SOLO_PCI_ERR);
-	struct solo_p2m_dev *p2m_dev;
-	int i;
-
-	if (!(err & (SOLO_PCI_ERR_P2M | SOLO_PCI_ERR_P2M_DESC)))
-		return;
-
-	for (i = 0; i < SOLO_NR_P2M; i++) {
-		p2m_dev = &solo_dev->p2m_dev[i];
-		p2m_dev->error = 1;
-		solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
-		complete(&p2m_dev->completion);
-	}
-}
-
-void solo_p2m_exit(struct solo_dev *solo_dev)
-{
-	int i;
-
-	for (i = 0; i < SOLO_NR_P2M; i++)
-		solo_irq_off(solo_dev, SOLO_IRQ_P2M(i));
-}
-
-static int solo_p2m_test(struct solo_dev *solo_dev, int base, int size)
-{
-	u32 *wr_buf;
-	u32 *rd_buf;
-	int i;
-	int ret = -EIO;
-	int order = get_order(size);
-
-	wr_buf = (u32 *)__get_free_pages(GFP_KERNEL, order);
-	if (wr_buf == NULL)
-		return -1;
-
-	rd_buf = (u32 *)__get_free_pages(GFP_KERNEL, order);
-	if (rd_buf == NULL) {
-		free_pages((unsigned long)wr_buf, order);
-		return -1;
-	}
-
-	for (i = 0; i < (size >> 3); i++)
-		*(wr_buf + i) = (i << 16) | (i + 1);
-
-	for (i = (size >> 3); i < (size >> 2); i++)
-		*(wr_buf + i) = ~((i << 16) | (i + 1));
-
-	memset(rd_buf, 0x55, size);
-
-	if (solo_p2m_dma(solo_dev, 1, wr_buf, base, size, 0, 0))
-		goto test_fail;
-
-	if (solo_p2m_dma(solo_dev, 0, rd_buf, base, size, 0, 0))
-		goto test_fail;
-
-	for (i = 0; i < (size >> 2); i++) {
-		if (*(wr_buf + i) != *(rd_buf + i))
-			goto test_fail;
-	}
-
-	ret = 0;
-
-test_fail:
-	free_pages((unsigned long)wr_buf, order);
-	free_pages((unsigned long)rd_buf, order);
-
-	return ret;
-}
-
-int solo_p2m_init(struct solo_dev *solo_dev)
-{
-	struct solo_p2m_dev *p2m_dev;
-	int i;
-
-	for (i = 0; i < SOLO_NR_P2M; i++) {
-		p2m_dev = &solo_dev->p2m_dev[i];
-
-		mutex_init(&p2m_dev->mutex);
-		init_completion(&p2m_dev->completion);
-
-		solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
-		solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i),
-			       SOLO_P2M_CSC_16BIT_565 |
-			       SOLO_P2M_DESC_INTR_OPT |
-			       SOLO_P2M_DMA_INTERVAL(0) |
-			       SOLO_P2M_PCI_MASTER_MODE);
-		solo_irq_on(solo_dev, SOLO_IRQ_P2M(i));
-	}
-
-	/* Find correct SDRAM size */
-	for (solo_dev->sdram_size = 0, i = 2; i >= 0; i--) {
-		solo_reg_write(solo_dev, SOLO_DMA_CTRL,
-			       SOLO_DMA_CTRL_REFRESH_CYCLE(1) |
-			       SOLO_DMA_CTRL_SDRAM_SIZE(i) |
-			       SOLO_DMA_CTRL_SDRAM_CLK_INVERT |
-			       SOLO_DMA_CTRL_READ_CLK_SELECT |
-			       SOLO_DMA_CTRL_LATENCY(1));
-
-		solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config |
-			       SOLO_SYS_CFG_RESET);
-		solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config);
-
-		switch (i) {
-		case 2:
-			if (solo_p2m_test(solo_dev, 0x07ff0000, 0x00010000) ||
-			    solo_p2m_test(solo_dev, 0x05ff0000, 0x00010000))
-				continue;
-			break;
-
-		case 1:
-			if (solo_p2m_test(solo_dev, 0x03ff0000, 0x00010000))
-				continue;
-			break;
-
-		default:
-			if (solo_p2m_test(solo_dev, 0x01ff0000, 0x00010000))
-				continue;
-		}
-
-		solo_dev->sdram_size = (32 << 20) << i;
-		break;
-	}
-
-	if (!solo_dev->sdram_size) {
-		dev_err(&solo_dev->pdev->dev, "Error detecting SDRAM size\n");
-		return -EIO;
-	}
-
-	if (SOLO_SDRAM_END(solo_dev) > solo_dev->sdram_size) {
-		dev_err(&solo_dev->pdev->dev,
-			"SDRAM is not large enough (%u < %u)\n",
-			solo_dev->sdram_size, SOLO_SDRAM_END(solo_dev));
-		return -EIO;
-	}
-
-	return 0;
-}
diff --git a/drivers/staging/media/solo6x10/solo6x10-regs.h b/drivers/staging/media/solo6x10/solo6x10-regs.h
deleted file mode 100644
index e34ac56ab101e..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10-regs.h
+++ /dev/null
@@ -1,635 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-#ifndef __SOLO6X10_REGISTERS_H
-#define __SOLO6X10_REGISTERS_H
-
-#include "solo6x10-offsets.h"
-
-/* Global 6010 system configuration */
-#define SOLO_SYS_CFG				0x0000
-#define   SOLO_SYS_CFG_FOUT_EN			0x00000001
-#define   SOLO_SYS_CFG_PLL_BYPASS		0x00000002
-#define   SOLO_SYS_CFG_PLL_PWDN			0x00000004
-#define   SOLO_SYS_CFG_OUTDIV(__n)		(((__n) & 0x003) << 3)
-#define   SOLO_SYS_CFG_FEEDBACKDIV(__n)		(((__n) & 0x1ff) << 5)
-#define   SOLO_SYS_CFG_INPUTDIV(__n)		(((__n) & 0x01f) << 14)
-#define   SOLO_SYS_CFG_CLOCK_DIV		0x00080000
-#define   SOLO_SYS_CFG_NCLK_DELAY(__n)		(((__n) & 0x003) << 24)
-#define   SOLO_SYS_CFG_PCLK_DELAY(__n)		(((__n) & 0x00f) << 26)
-#define   SOLO_SYS_CFG_SDRAM64BIT		0x40000000
-#define   SOLO_SYS_CFG_RESET			0x80000000
-
-#define	SOLO_DMA_CTRL				0x0004
-#define	  SOLO_DMA_CTRL_REFRESH_CYCLE(n)	((n)<<8)
-/* 0=16/32MB, 1=32/64MB, 2=64/128MB, 3=128/256MB */
-#define	  SOLO_DMA_CTRL_SDRAM_SIZE(n)		((n)<<6)
-#define	  SOLO_DMA_CTRL_SDRAM_CLK_INVERT	(1<<5)
-#define	  SOLO_DMA_CTRL_STROBE_SELECT		(1<<4)
-#define	  SOLO_DMA_CTRL_READ_DATA_SELECT	(1<<3)
-#define	  SOLO_DMA_CTRL_READ_CLK_SELECT		(1<<2)
-#define	  SOLO_DMA_CTRL_LATENCY(n)		((n)<<0)
-
-/* Some things we set in this are undocumented. Why Softlogic?!?! */
-#define SOLO_DMA_CTRL1				0x0008
-
-#define SOLO_SYS_VCLK				0x000C
-#define	  SOLO_VCLK_INVERT			(1<<22)
-/* 0=sys_clk/4, 1=sys_clk/2, 2=clk_in/2 of system input */
-#define	  SOLO_VCLK_SELECT(n)			((n)<<20)
-#define	  SOLO_VCLK_VIN1415_DELAY(n)		((n)<<14)
-#define	  SOLO_VCLK_VIN1213_DELAY(n)		((n)<<12)
-#define	  SOLO_VCLK_VIN1011_DELAY(n)		((n)<<10)
-#define	  SOLO_VCLK_VIN0809_DELAY(n)		((n)<<8)
-#define	  SOLO_VCLK_VIN0607_DELAY(n)		((n)<<6)
-#define	  SOLO_VCLK_VIN0405_DELAY(n)		((n)<<4)
-#define	  SOLO_VCLK_VIN0203_DELAY(n)		((n)<<2)
-#define	  SOLO_VCLK_VIN0001_DELAY(n)		((n)<<0)
-
-#define SOLO_IRQ_STAT				0x0010
-#define SOLO_IRQ_MASK				0x0014
-#define	  SOLO_IRQ_P2M(n)			(1<<((n)+17))
-#define	  SOLO_IRQ_GPIO				(1<<16)
-#define	  SOLO_IRQ_VIDEO_LOSS			(1<<15)
-#define	  SOLO_IRQ_VIDEO_IN			(1<<14)
-#define	  SOLO_IRQ_MOTION			(1<<13)
-#define	  SOLO_IRQ_ATA_CMD			(1<<12)
-#define	  SOLO_IRQ_ATA_DIR			(1<<11)
-#define	  SOLO_IRQ_PCI_ERR			(1<<10)
-#define	  SOLO_IRQ_PS2_1			(1<<9)
-#define	  SOLO_IRQ_PS2_0			(1<<8)
-#define	  SOLO_IRQ_SPI				(1<<7)
-#define	  SOLO_IRQ_IIC				(1<<6)
-#define	  SOLO_IRQ_UART(n)			(1<<((n) + 4))
-#define	  SOLO_IRQ_G723				(1<<3)
-#define	  SOLO_IRQ_DECODER			(1<<1)
-#define	  SOLO_IRQ_ENCODER			(1<<0)
-
-#define SOLO_CHIP_OPTION			0x001C
-#define   SOLO_CHIP_ID_MASK			0x00000007
-
-#define SOLO_PLL_CONFIG				0x0020 /* 6110 Only */
-
-#define SOLO_EEPROM_CTRL			0x0060
-#define	  SOLO_EEPROM_ACCESS_EN			(1<<7)
-#define	  SOLO_EEPROM_CS			(1<<3)
-#define	  SOLO_EEPROM_CLK			(1<<2)
-#define	  SOLO_EEPROM_DO			(1<<1)
-#define	  SOLO_EEPROM_DI			(1<<0)
-#define	  SOLO_EEPROM_ENABLE (SOLO_EEPROM_ACCESS_EN | SOLO_EEPROM_CS)
-
-#define SOLO_PCI_ERR				0x0070
-#define   SOLO_PCI_ERR_FATAL			0x00000001
-#define   SOLO_PCI_ERR_PARITY			0x00000002
-#define   SOLO_PCI_ERR_TARGET			0x00000004
-#define   SOLO_PCI_ERR_TIMEOUT			0x00000008
-#define   SOLO_PCI_ERR_P2M			0x00000010
-#define   SOLO_PCI_ERR_ATA			0x00000020
-#define   SOLO_PCI_ERR_P2M_DESC			0x00000040
-#define   SOLO_PCI_ERR_FSM0(__s)		(((__s) >> 16) & 0x0f)
-#define   SOLO_PCI_ERR_FSM1(__s)		(((__s) >> 20) & 0x0f)
-#define   SOLO_PCI_ERR_FSM2(__s)		(((__s) >> 24) & 0x1f)
-
-#define SOLO_P2M_BASE				0x0080
-
-#define SOLO_P2M_CONFIG(n)			(0x0080 + ((n)*0x20))
-#define	  SOLO_P2M_DMA_INTERVAL(n)		((n)<<6)/* N*32 clocks */
-#define	  SOLO_P2M_CSC_BYTE_REORDER		(1<<5)	/* BGR -> RGB */
-/* 0:r=[14:10] g=[9:5] b=[4:0], 1:r=[15:11] g=[10:5] b=[4:0] */
-#define	  SOLO_P2M_CSC_16BIT_565		(1<<4)
-#define	  SOLO_P2M_UV_SWAP			(1<<3)
-#define	  SOLO_P2M_PCI_MASTER_MODE		(1<<2)
-#define	  SOLO_P2M_DESC_INTR_OPT		(1<<1)	/* 1:Empty, 0:Each */
-#define	  SOLO_P2M_DESC_MODE			(1<<0)
-
-#define SOLO_P2M_DES_ADR(n)			(0x0084 + ((n)*0x20))
-
-#define SOLO_P2M_DESC_ID(n)			(0x0088 + ((n)*0x20))
-#define	  SOLO_P2M_UPDATE_ID(n)			((n)<<0)
-
-#define SOLO_P2M_STATUS(n)			(0x008C + ((n)*0x20))
-#define	  SOLO_P2M_COMMAND_DONE			(1<<8)
-#define	  SOLO_P2M_CURRENT_ID(stat)		(0xff & (stat))
-
-#define SOLO_P2M_CONTROL(n)			(0x0090 + ((n)*0x20))
-#define	  SOLO_P2M_PCI_INC(n)			((n)<<20)
-#define	  SOLO_P2M_REPEAT(n)			((n)<<10)
-/* 0:512, 1:256, 2:128, 3:64, 4:32, 5:128(2page) */
-#define	  SOLO_P2M_BURST_SIZE(n)		((n)<<7)
-#define	    SOLO_P2M_BURST_512			0
-#define	    SOLO_P2M_BURST_256			1
-#define	    SOLO_P2M_BURST_128			2
-#define	    SOLO_P2M_BURST_64			3
-#define	    SOLO_P2M_BURST_32			4
-#define	  SOLO_P2M_CSC_16BIT			(1<<6)	/* 0:24bit, 1:16bit */
-/* 0:Y[0]<-0(OFF), 1:Y[0]<-1(ON), 2:Y[0]<-G[0], 3:Y[0]<-Bit[15] */
-#define	  SOLO_P2M_ALPHA_MODE(n)		((n)<<4)
-#define	  SOLO_P2M_CSC_ON			(1<<3)
-#define	  SOLO_P2M_INTERRUPT_REQ		(1<<2)
-#define	  SOLO_P2M_WRITE			(1<<1)
-#define	  SOLO_P2M_TRANS_ON			(1<<0)
-
-#define SOLO_P2M_EXT_CFG(n)			(0x0094 + ((n)*0x20))
-#define	  SOLO_P2M_EXT_INC(n)			((n)<<20)
-#define	  SOLO_P2M_COPY_SIZE(n)			((n)<<0)
-
-#define SOLO_P2M_TAR_ADR(n)			(0x0098 + ((n)*0x20))
-
-#define SOLO_P2M_EXT_ADR(n)			(0x009C + ((n)*0x20))
-
-#define SOLO_P2M_BUFFER(i)			(0x2000 + ((i)*4))
-
-#define SOLO_VI_CH_SWITCH_0			0x0100
-#define SOLO_VI_CH_SWITCH_1			0x0104
-#define SOLO_VI_CH_SWITCH_2			0x0108
-
-#define	SOLO_VI_CH_ENA				0x010C
-#define	SOLO_VI_CH_FORMAT			0x0110
-#define	  SOLO_VI_FD_SEL_MASK(n)		((n)<<16)
-#define	  SOLO_VI_PROG_MASK(n)			((n)<<0)
-
-#define SOLO_VI_FMT_CFG				0x0114
-#define	  SOLO_VI_FMT_CHECK_VCOUNT		(1<<31)
-#define	  SOLO_VI_FMT_CHECK_HCOUNT		(1<<30)
-#define   SOLO_VI_FMT_TEST_SIGNAL		(1<<28)
-
-#define	SOLO_VI_PAGE_SW				0x0118
-#define	  SOLO_FI_INV_DISP_LIVE(n)		((n)<<8)
-#define	  SOLO_FI_INV_DISP_OUT(n)		((n)<<7)
-#define	  SOLO_DISP_SYNC_FI(n)			((n)<<6)
-#define	  SOLO_PIP_PAGE_ADD(n)			((n)<<3)
-#define	  SOLO_NORMAL_PAGE_ADD(n)		((n)<<0)
-
-#define	SOLO_VI_ACT_I_P				0x011C
-#define	SOLO_VI_ACT_I_S				0x0120
-#define	SOLO_VI_ACT_P				0x0124
-#define	  SOLO_VI_FI_INVERT			(1<<31)
-#define	  SOLO_VI_H_START(n)			((n)<<21)
-#define	  SOLO_VI_V_START(n)			((n)<<11)
-#define	  SOLO_VI_V_STOP(n)			((n)<<0)
-
-#define SOLO_VI_STATUS0				0x0128
-#define   SOLO_VI_STATUS0_PAGE(__n)		((__n) & 0x07)
-#define SOLO_VI_STATUS1				0x012C
-
-/* XXX: Might be better off in kernel level disp.h */
-#define DISP_PAGE(stat)				((stat) & 0x07)
-
-#define SOLO_VI_PB_CONFIG			0x0130
-#define	  SOLO_VI_PB_USER_MODE			(1<<1)
-#define	  SOLO_VI_PB_PAL			(1<<0)
-#define SOLO_VI_PB_RANGE_HV			0x0134
-#define	  SOLO_VI_PB_HSIZE(h)			((h)<<12)
-#define	  SOLO_VI_PB_VSIZE(v)			((v)<<0)
-#define SOLO_VI_PB_ACT_H			0x0138
-#define	  SOLO_VI_PB_HSTART(n)			((n)<<12)
-#define	  SOLO_VI_PB_HSTOP(n)			((n)<<0)
-#define SOLO_VI_PB_ACT_V			0x013C
-#define	  SOLO_VI_PB_VSTART(n)			((n)<<12)
-#define	  SOLO_VI_PB_VSTOP(n)			((n)<<0)
-
-#define	SOLO_VI_MOSAIC(ch)			(0x0140 + ((ch)*4))
-#define	  SOLO_VI_MOSAIC_SX(x)			((x)<<24)
-#define	  SOLO_VI_MOSAIC_EX(x)			((x)<<16)
-#define	  SOLO_VI_MOSAIC_SY(x)			((x)<<8)
-#define	  SOLO_VI_MOSAIC_EY(x)			((x)<<0)
-
-#define	SOLO_VI_WIN_CTRL0(ch)			(0x0180 + ((ch)*4))
-#define	SOLO_VI_WIN_CTRL1(ch)			(0x01C0 + ((ch)*4))
-
-#define	  SOLO_VI_WIN_CHANNEL(n)		((n)<<28)
-
-#define	  SOLO_VI_WIN_PIP(n)			((n)<<27)
-#define	  SOLO_VI_WIN_SCALE(n)			((n)<<24)
-
-#define	  SOLO_VI_WIN_SX(x)			((x)<<12)
-#define	  SOLO_VI_WIN_EX(x)			((x)<<0)
-
-#define	  SOLO_VI_WIN_SY(x)			((x)<<12)
-#define	  SOLO_VI_WIN_EY(x)			((x)<<0)
-
-#define	SOLO_VI_WIN_ON(ch)			(0x0200 + ((ch)*4))
-
-#define SOLO_VI_WIN_SW				0x0240
-#define SOLO_VI_WIN_LIVE_AUTO_MUTE		0x0244
-
-#define	SOLO_VI_MOT_ADR				0x0260
-#define	  SOLO_VI_MOTION_EN(mask)		((mask)<<16)
-#define	SOLO_VI_MOT_CTRL			0x0264
-#define	  SOLO_VI_MOTION_FRAME_COUNT(n)		((n)<<24)
-#define	  SOLO_VI_MOTION_SAMPLE_LENGTH(n)	((n)<<16)
-#define	  SOLO_VI_MOTION_INTR_START_STOP	(1<<15)
-#define	  SOLO_VI_MOTION_FREEZE_DATA		(1<<14)
-#define	  SOLO_VI_MOTION_SAMPLE_COUNT(n)	((n)<<0)
-#define SOLO_VI_MOT_CLEAR			0x0268
-#define SOLO_VI_MOT_STATUS			0x026C
-#define	  SOLO_VI_MOTION_CNT(n)			((n)<<0)
-#define SOLO_VI_MOTION_BORDER			0x0270
-#define SOLO_VI_MOTION_BAR			0x0274
-#define	  SOLO_VI_MOTION_Y_SET			(1<<29)
-#define	  SOLO_VI_MOTION_Y_ADD			(1<<28)
-#define	  SOLO_VI_MOTION_CB_SET			(1<<27)
-#define	  SOLO_VI_MOTION_CB_ADD			(1<<26)
-#define	  SOLO_VI_MOTION_CR_SET			(1<<25)
-#define	  SOLO_VI_MOTION_CR_ADD			(1<<24)
-#define	  SOLO_VI_MOTION_Y_VALUE(v)		((v)<<16)
-#define	  SOLO_VI_MOTION_CB_VALUE(v)		((v)<<8)
-#define	  SOLO_VI_MOTION_CR_VALUE(v)		((v)<<0)
-
-#define	SOLO_VO_FMT_ENC				0x0300
-#define	  SOLO_VO_SCAN_MODE_PROGRESSIVE		(1<<31)
-#define	  SOLO_VO_FMT_TYPE_PAL			(1<<30)
-#define   SOLO_VO_FMT_TYPE_NTSC			0
-#define	  SOLO_VO_USER_SET			(1<<29)
-
-#define	  SOLO_VO_FI_CHANGE			(1<<20)
-#define	  SOLO_VO_USER_COLOR_SET_VSYNC		(1<<19)
-#define	  SOLO_VO_USER_COLOR_SET_HSYNC		(1<<18)
-#define	  SOLO_VO_USER_COLOR_SET_NAH		(1<<17)
-#define	  SOLO_VO_USER_COLOR_SET_NAV		(1<<16)
-#define	  SOLO_VO_NA_COLOR_Y(Y)			((Y)<<8)
-#define	  SOLO_VO_NA_COLOR_CB(CB)		(((CB)/16)<<4)
-#define	  SOLO_VO_NA_COLOR_CR(CR)		(((CR)/16)<<0)
-
-#define	SOLO_VO_ACT_H				0x0304
-#define	  SOLO_VO_H_BLANK(n)			((n)<<22)
-#define	  SOLO_VO_H_START(n)			((n)<<11)
-#define	  SOLO_VO_H_STOP(n)			((n)<<0)
-
-#define	SOLO_VO_ACT_V				0x0308
-#define	  SOLO_VO_V_BLANK(n)			((n)<<22)
-#define	  SOLO_VO_V_START(n)			((n)<<11)
-#define	  SOLO_VO_V_STOP(n)			((n)<<0)
-
-#define	SOLO_VO_RANGE_HV			0x030C
-#define	  SOLO_VO_SYNC_INVERT			(1<<24)
-#define	  SOLO_VO_HSYNC_INVERT			(1<<23)
-#define	  SOLO_VO_VSYNC_INVERT			(1<<22)
-#define	  SOLO_VO_H_LEN(n)			((n)<<11)
-#define	  SOLO_VO_V_LEN(n)			((n)<<0)
-
-#define	SOLO_VO_DISP_CTRL			0x0310
-#define	  SOLO_VO_DISP_ON			(1<<31)
-#define	  SOLO_VO_DISP_ERASE_COUNT(n)		((n&0xf)<<24)
-#define	  SOLO_VO_DISP_DOUBLE_SCAN		(1<<22)
-#define	  SOLO_VO_DISP_SINGLE_PAGE		(1<<21)
-#define	  SOLO_VO_DISP_BASE(n)			(((n)>>16) & 0xffff)
-
-#define SOLO_VO_DISP_ERASE			0x0314
-#define	  SOLO_VO_DISP_ERASE_ON			(1<<0)
-
-#define	SOLO_VO_ZOOM_CTRL			0x0318
-#define	  SOLO_VO_ZOOM_VER_ON			(1<<24)
-#define	  SOLO_VO_ZOOM_HOR_ON			(1<<23)
-#define	  SOLO_VO_ZOOM_V_COMP			(1<<22)
-#define	  SOLO_VO_ZOOM_SX(h)			(((h)/2)<<11)
-#define	  SOLO_VO_ZOOM_SY(v)			(((v)/2)<<0)
-
-#define SOLO_VO_FREEZE_CTRL			0x031C
-#define	  SOLO_VO_FREEZE_ON			(1<<1)
-#define	  SOLO_VO_FREEZE_INTERPOLATION		(1<<0)
-
-#define	SOLO_VO_BKG_COLOR			0x0320
-#define	  SOLO_BG_Y(y)				((y)<<16)
-#define	  SOLO_BG_U(u)				((u)<<8)
-#define	  SOLO_BG_V(v)				((v)<<0)
-
-#define	SOLO_VO_DEINTERLACE			0x0324
-#define	  SOLO_VO_DEINTERLACE_THRESHOLD(n)	((n)<<8)
-#define	  SOLO_VO_DEINTERLACE_EDGE_VALUE(n)	((n)<<0)
-
-#define SOLO_VO_BORDER_LINE_COLOR		0x0330
-#define SOLO_VO_BORDER_FILL_COLOR		0x0334
-#define SOLO_VO_BORDER_LINE_MASK		0x0338
-#define SOLO_VO_BORDER_FILL_MASK		0x033c
-
-#define SOLO_VO_BORDER_X(n)			(0x0340+((n)*4))
-#define SOLO_VO_BORDER_Y(n)			(0x0354+((n)*4))
-
-#define SOLO_VO_CELL_EXT_SET			0x0368
-#define SOLO_VO_CELL_EXT_START			0x036c
-#define SOLO_VO_CELL_EXT_STOP			0x0370
-
-#define SOLO_VO_CELL_EXT_SET2			0x0374
-#define SOLO_VO_CELL_EXT_START2			0x0378
-#define SOLO_VO_CELL_EXT_STOP2			0x037c
-
-#define SOLO_VO_RECTANGLE_CTRL(n)		(0x0368+((n)*12))
-#define SOLO_VO_RECTANGLE_START(n)		(0x036c+((n)*12))
-#define SOLO_VO_RECTANGLE_STOP(n)		(0x0370+((n)*12))
-
-#define SOLO_VO_CURSOR_POS			(0x0380)
-#define SOLO_VO_CURSOR_CLR			(0x0384)
-#define SOLO_VO_CURSOR_CLR2			(0x0388)
-#define SOLO_VO_CURSOR_MASK(id)			(0x0390+((id)*4))
-
-#define SOLO_VO_EXPANSION(id)			(0x0250+((id)*4))
-
-#define	SOLO_OSG_CONFIG				0x03E0
-#define	  SOLO_VO_OSG_ON			(1<<31)
-#define	  SOLO_VO_OSG_COLOR_MUTE		(1<<28)
-#define	  SOLO_VO_OSG_ALPHA_RATE(n)		((n)<<22)
-#define	  SOLO_VO_OSG_ALPHA_BG_RATE(n)		((n)<<16)
-#define	  SOLO_VO_OSG_BASE(offset)		(((offset)>>16)&0xffff)
-
-#define SOLO_OSG_ERASE				0x03E4
-#define	  SOLO_OSG_ERASE_ON			(0x80)
-#define	  SOLO_OSG_ERASE_OFF			(0x00)
-
-#define SOLO_VO_OSG_BLINK			0x03E8
-#define	  SOLO_VO_OSG_BLINK_ON			(1<<1)
-#define	  SOLO_VO_OSG_BLINK_INTREVAL18		(1<<0)
-
-#define SOLO_CAP_BASE				0x0400
-#define	  SOLO_CAP_MAX_PAGE(n)			((n)<<16)
-#define	  SOLO_CAP_BASE_ADDR(n)			((n)<<0)
-#define SOLO_CAP_BTW				0x0404
-#define	  SOLO_CAP_PROG_BANDWIDTH(n)		((n)<<8)
-#define	  SOLO_CAP_MAX_BANDWIDTH(n)		((n)<<0)
-
-#define SOLO_DIM_SCALE1				0x0408
-#define SOLO_DIM_SCALE2				0x040C
-#define SOLO_DIM_SCALE3				0x0410
-#define SOLO_DIM_SCALE4				0x0414
-#define SOLO_DIM_SCALE5				0x0418
-#define	  SOLO_DIM_V_MB_NUM_FRAME(n)		((n)<<16)
-#define	  SOLO_DIM_V_MB_NUM_FIELD(n)		((n)<<8)
-#define	  SOLO_DIM_H_MB_NUM(n)			((n)<<0)
-
-#define SOLO_DIM_PROG				0x041C
-#define SOLO_CAP_STATUS				0x0420
-
-#define SOLO_CAP_CH_SCALE(ch)			(0x0440+((ch)*4))
-#define SOLO_CAP_CH_COMP_ENA_E(ch)		(0x0480+((ch)*4))
-#define SOLO_CAP_CH_INTV(ch)			(0x04C0+((ch)*4))
-#define SOLO_CAP_CH_INTV_E(ch)			(0x0500+((ch)*4))
-
-
-#define SOLO_VE_CFG0				0x0610
-#define	  SOLO_VE_TWO_PAGE_MODE			(1<<31)
-#define	  SOLO_VE_INTR_CTRL(n)			((n)<<24)
-#define	  SOLO_VE_BLOCK_SIZE(n)			((n)<<16)
-#define	  SOLO_VE_BLOCK_BASE(n)			((n)<<0)
-
-#define SOLO_VE_CFG1				0x0614
-#define	  SOLO_VE_BYTE_ALIGN(n)			((n)<<24)
-#define	  SOLO_VE_INSERT_INDEX			(1<<18)
-#define	  SOLO_VE_MOTION_MODE(n)		((n)<<16)
-#define	  SOLO_VE_MOTION_BASE(n)		((n)<<0)
-#define   SOLO_VE_MPEG_SIZE_H(n)		((n)<<28) /* 6110 Only */
-#define   SOLO_VE_JPEG_SIZE_H(n)		((n)<<20) /* 6110 Only */
-#define   SOLO_VE_INSERT_INDEX_JPEG		(1<<19)   /* 6110 Only */
-
-#define SOLO_VE_WMRK_POLY			0x061C
-#define SOLO_VE_VMRK_INIT_KEY			0x0620
-#define SOLO_VE_WMRK_STRL			0x0624
-#define SOLO_VE_ENCRYP_POLY			0x0628
-#define SOLO_VE_ENCRYP_INIT			0x062C
-#define SOLO_VE_ATTR				0x0630
-#define	  SOLO_VE_LITTLE_ENDIAN			(1<<31)
-#define	  SOLO_COMP_ATTR_RN			(1<<30)
-#define	  SOLO_COMP_ATTR_FCODE(n)		((n)<<27)
-#define	  SOLO_COMP_TIME_INC(n)			((n)<<25)
-#define	  SOLO_COMP_TIME_WIDTH(n)		((n)<<21)
-#define	  SOLO_DCT_INTERVAL(n)			((n)<<16)
-#define SOLO_VE_COMPT_MOT			0x0634 /* 6110 Only */
-
-#define SOLO_VE_STATE(n)			(0x0640+((n)*4))
-
-#define SOLO_VE_JPEG_QP_TBL			0x0670
-#define SOLO_VE_JPEG_QP_CH_L			0x0674
-#define SOLO_VE_JPEG_QP_CH_H			0x0678
-#define SOLO_VE_JPEG_CFG			0x067C
-#define SOLO_VE_JPEG_CTRL			0x0680
-#define SOLO_VE_CODE_ENCRYPT			0x0684 /* 6110 Only */
-#define SOLO_VE_JPEG_CFG1			0x0688 /* 6110 Only */
-#define SOLO_VE_WMRK_ENABLE			0x068C /* 6110 Only */
-#define SOLO_VE_OSD_CH				0x0690
-#define SOLO_VE_OSD_BASE			0x0694
-#define SOLO_VE_OSD_CLR				0x0698
-#define SOLO_VE_OSD_OPT				0x069C
-#define   SOLO_VE_OSD_V_DOUBLE			(1<<16) /* 6110 Only */
-#define   SOLO_VE_OSD_H_SHADOW			(1<<15)
-#define   SOLO_VE_OSD_V_SHADOW			(1<<14)
-#define   SOLO_VE_OSD_H_OFFSET(n)		((n & 0x7f)<<7)
-#define   SOLO_VE_OSD_V_OFFSET(n)		(n & 0x7f)
-
-#define SOLO_VE_CH_INTL(ch)			(0x0700+((ch)*4))
-#define SOLO_VE_CH_MOT(ch)			(0x0740+((ch)*4))
-#define SOLO_VE_CH_QP(ch)			(0x0780+((ch)*4))
-#define SOLO_VE_CH_QP_E(ch)			(0x07C0+((ch)*4))
-#define SOLO_VE_CH_GOP(ch)			(0x0800+((ch)*4))
-#define SOLO_VE_CH_GOP_E(ch)			(0x0840+((ch)*4))
-#define SOLO_VE_CH_REF_BASE(ch)			(0x0880+((ch)*4))
-#define SOLO_VE_CH_REF_BASE_E(ch)		(0x08C0+((ch)*4))
-
-#define SOLO_VE_MPEG4_QUE(n)			(0x0A00+((n)*8))
-#define SOLO_VE_JPEG_QUE(n)			(0x0A04+((n)*8))
-
-#define SOLO_VD_CFG0				0x0900
-#define	  SOLO_VD_CFG_NO_WRITE_NO_WINDOW	(1<<24)
-#define	  SOLO_VD_CFG_BUSY_WIAT_CODE		(1<<23)
-#define	  SOLO_VD_CFG_BUSY_WIAT_REF		(1<<22)
-#define	  SOLO_VD_CFG_BUSY_WIAT_RES		(1<<21)
-#define	  SOLO_VD_CFG_BUSY_WIAT_MS		(1<<20)
-#define	  SOLO_VD_CFG_SINGLE_MODE		(1<<18)
-#define	  SOLO_VD_CFG_SCAL_MANUAL		(1<<17)
-#define	  SOLO_VD_CFG_USER_PAGE_CTRL		(1<<16)
-#define	  SOLO_VD_CFG_LITTLE_ENDIAN		(1<<15)
-#define	  SOLO_VD_CFG_START_FI			(1<<14)
-#define	  SOLO_VD_CFG_ERR_LOCK			(1<<13)
-#define	  SOLO_VD_CFG_ERR_INT_ENA		(1<<12)
-#define	  SOLO_VD_CFG_TIME_WIDTH(n)		((n)<<8)
-#define	  SOLO_VD_CFG_DCT_INTERVAL(n)		((n)<<0)
-
-#define SOLO_VD_CFG1				0x0904
-
-#define	SOLO_VD_DEINTERLACE			0x0908
-#define	  SOLO_VD_DEINTERLACE_THRESHOLD(n)	((n)<<8)
-#define	  SOLO_VD_DEINTERLACE_EDGE_VALUE(n)	((n)<<0)
-
-#define SOLO_VD_CODE_ADR			0x090C
-
-#define SOLO_VD_CTRL				0x0910
-#define	  SOLO_VD_OPER_ON			(1<<31)
-#define	  SOLO_VD_MAX_ITEM(n)			((n)<<0)
-
-#define SOLO_VD_STATUS0				0x0920
-#define	  SOLO_VD_STATUS0_INTR_ACK		(1<<22)
-#define	  SOLO_VD_STATUS0_INTR_EMPTY		(1<<21)
-#define	  SOLO_VD_STATUS0_INTR_ERR		(1<<20)
-
-#define SOLO_VD_STATUS1				0x0924
-
-#define SOLO_VD_IDX0				0x0930
-#define	  SOLO_VD_IDX_INTERLACE			(1<<30)
-#define	  SOLO_VD_IDX_CHANNEL(n)		((n)<<24)
-#define	  SOLO_VD_IDX_SIZE(n)			((n)<<0)
-
-#define SOLO_VD_IDX1				0x0934
-#define	  SOLO_VD_IDX_SRC_SCALE(n)		((n)<<28)
-#define	  SOLO_VD_IDX_WINDOW(n)			((n)<<24)
-#define	  SOLO_VD_IDX_DEINTERLACE		(1<<16)
-#define	  SOLO_VD_IDX_H_BLOCK(n)		((n)<<8)
-#define	  SOLO_VD_IDX_V_BLOCK(n)		((n)<<0)
-
-#define SOLO_VD_IDX2				0x0938
-#define	  SOLO_VD_IDX_REF_BASE_SIDE		(1<<31)
-#define	  SOLO_VD_IDX_REF_BASE(n)		(((n)>>16)&0xffff)
-
-#define SOLO_VD_IDX3				0x093C
-#define	  SOLO_VD_IDX_DISP_SCALE(n)		((n)<<28)
-#define	  SOLO_VD_IDX_INTERLACE_WR		(1<<27)
-#define	  SOLO_VD_IDX_INTERPOL			(1<<26)
-#define	  SOLO_VD_IDX_HOR2X			(1<<25)
-#define	  SOLO_VD_IDX_OFFSET_X(n)		((n)<<12)
-#define	  SOLO_VD_IDX_OFFSET_Y(n)		((n)<<0)
-
-#define SOLO_VD_IDX4				0x0940
-#define	  SOLO_VD_IDX_DEC_WR_PAGE(n)		((n)<<8)
-#define	  SOLO_VD_IDX_DISP_RD_PAGE(n)		((n)<<0)
-
-#define SOLO_VD_WR_PAGE(n)			(0x03F0 + ((n) * 4))
-
-
-#define SOLO_GPIO_CONFIG_0			0x0B00
-#define SOLO_GPIO_CONFIG_1			0x0B04
-#define SOLO_GPIO_DATA_OUT			0x0B08
-#define SOLO_GPIO_DATA_IN			0x0B0C
-#define SOLO_GPIO_INT_ACK_STA			0x0B10
-#define SOLO_GPIO_INT_ENA			0x0B14
-#define SOLO_GPIO_INT_CFG_0			0x0B18
-#define SOLO_GPIO_INT_CFG_1			0x0B1C
-
-
-#define SOLO_IIC_CFG				0x0B20
-#define	  SOLO_IIC_ENABLE			(1<<8)
-#define	  SOLO_IIC_PRESCALE(n)			((n)<<0)
-
-#define SOLO_IIC_CTRL				0x0B24
-#define	  SOLO_IIC_AUTO_CLEAR			(1<<20)
-#define	  SOLO_IIC_STATE_RX_ACK			(1<<19)
-#define	  SOLO_IIC_STATE_BUSY			(1<<18)
-#define	  SOLO_IIC_STATE_SIG_ERR		(1<<17)
-#define	  SOLO_IIC_STATE_TRNS			(1<<16)
-#define	  SOLO_IIC_CH_SET(n)			((n)<<5)
-#define	  SOLO_IIC_ACK_EN			(1<<4)
-#define	  SOLO_IIC_START			(1<<3)
-#define	  SOLO_IIC_STOP				(1<<2)
-#define	  SOLO_IIC_READ				(1<<1)
-#define	  SOLO_IIC_WRITE			(1<<0)
-
-#define SOLO_IIC_TXD				0x0B28
-#define SOLO_IIC_RXD				0x0B2C
-
-/*
- *	UART REGISTER
- */
-#define SOLO_UART_CONTROL(n)			(0x0BA0 + ((n)*0x20))
-#define	  SOLO_UART_CLK_DIV(n)			((n)<<24)
-#define	  SOLO_MODEM_CTRL_EN			(1<<20)
-#define	  SOLO_PARITY_ERROR_DROP		(1<<18)
-#define	  SOLO_IRQ_ERR_EN			(1<<17)
-#define	  SOLO_IRQ_RX_EN			(1<<16)
-#define	  SOLO_IRQ_TX_EN			(1<<15)
-#define	  SOLO_RX_EN				(1<<14)
-#define	  SOLO_TX_EN				(1<<13)
-#define	  SOLO_UART_HALF_DUPLEX			(1<<12)
-#define	  SOLO_UART_LOOPBACK			(1<<11)
-
-#define	  SOLO_BAUDRATE_230400			((0<<9)|(0<<6))
-#define	  SOLO_BAUDRATE_115200			((0<<9)|(1<<6))
-#define	  SOLO_BAUDRATE_57600			((0<<9)|(2<<6))
-#define	  SOLO_BAUDRATE_38400			((0<<9)|(3<<6))
-#define	  SOLO_BAUDRATE_19200			((0<<9)|(4<<6))
-#define	  SOLO_BAUDRATE_9600			((0<<9)|(5<<6))
-#define	  SOLO_BAUDRATE_4800			((0<<9)|(6<<6))
-#define	  SOLO_BAUDRATE_2400			((1<<9)|(6<<6))
-#define	  SOLO_BAUDRATE_1200			((2<<9)|(6<<6))
-#define	  SOLO_BAUDRATE_300			((3<<9)|(6<<6))
-
-#define	  SOLO_UART_DATA_BIT_8			(3<<4)
-#define	  SOLO_UART_DATA_BIT_7			(2<<4)
-#define	  SOLO_UART_DATA_BIT_6			(1<<4)
-#define	  SOLO_UART_DATA_BIT_5			(0<<4)
-
-#define	  SOLO_UART_STOP_BIT_1			(0<<2)
-#define	  SOLO_UART_STOP_BIT_2			(1<<2)
-
-#define	  SOLO_UART_PARITY_NONE			(0<<0)
-#define	  SOLO_UART_PARITY_EVEN			(2<<0)
-#define	  SOLO_UART_PARITY_ODD			(3<<0)
-
-#define SOLO_UART_STATUS(n)			(0x0BA4 + ((n)*0x20))
-#define	  SOLO_UART_CTS				(1<<15)
-#define	  SOLO_UART_RX_BUSY			(1<<14)
-#define	  SOLO_UART_OVERRUN			(1<<13)
-#define	  SOLO_UART_FRAME_ERR			(1<<12)
-#define	  SOLO_UART_PARITY_ERR			(1<<11)
-#define	  SOLO_UART_TX_BUSY			(1<<5)
-
-#define	  SOLO_UART_RX_BUFF_CNT(stat)		(((stat)>>6) & 0x1f)
-#define	  SOLO_UART_RX_BUFF_SIZE		8
-#define	  SOLO_UART_TX_BUFF_CNT(stat)		(((stat)>>0) & 0x1f)
-#define	  SOLO_UART_TX_BUFF_SIZE		8
-
-#define SOLO_UART_TX_DATA(n)			(0x0BA8 + ((n)*0x20))
-#define	  SOLO_UART_TX_DATA_PUSH		(1<<8)
-#define SOLO_UART_RX_DATA(n)			(0x0BAC + ((n)*0x20))
-#define	  SOLO_UART_RX_DATA_POP			(1<<8)
-
-#define SOLO_TIMER_CLOCK_NUM			0x0be0
-#define SOLO_TIMER_USEC				0x0be8
-#define SOLO_TIMER_SEC				0x0bec
-#define SOLO_TIMER_USEC_LSB			0x0d20 /* 6110 Only */
-
-#define SOLO_AUDIO_CONTROL			0x0D00
-#define	  SOLO_AUDIO_ENABLE			(1<<31)
-#define	  SOLO_AUDIO_MASTER_MODE		(1<<30)
-#define	  SOLO_AUDIO_I2S_MODE			(1<<29)
-#define	  SOLO_AUDIO_I2S_LR_SWAP		(1<<27)
-#define	  SOLO_AUDIO_I2S_8BIT			(1<<26)
-#define	  SOLO_AUDIO_I2S_MULTI(n)		((n)<<24)
-#define	  SOLO_AUDIO_MIX_9TO0			(1<<23)
-#define	  SOLO_AUDIO_DEC_9TO0_VOL(n)		((n)<<20)
-#define	  SOLO_AUDIO_MIX_19TO10			(1<<19)
-#define	  SOLO_AUDIO_DEC_19TO10_VOL(n)		((n)<<16)
-#define	  SOLO_AUDIO_MODE(n)			((n)<<0)
-#define SOLO_AUDIO_SAMPLE			0x0D04
-#define	  SOLO_AUDIO_EE_MODE_ON			(1<<30)
-#define	  SOLO_AUDIO_EE_ENC_CH(ch)		((ch)<<25)
-#define	  SOLO_AUDIO_BITRATE(n)			((n)<<16)
-#define	  SOLO_AUDIO_CLK_DIV(n)			((n)<<0)
-#define SOLO_AUDIO_FDMA_INTR			0x0D08
-#define	  SOLO_AUDIO_FDMA_INTERVAL(n)		((n)<<19)
-#define	  SOLO_AUDIO_INTR_ORDER(n)		((n)<<16)
-#define	  SOLO_AUDIO_FDMA_BASE(n)		((n)<<0)
-#define SOLO_AUDIO_EVOL_0			0x0D0C
-#define SOLO_AUDIO_EVOL_1			0x0D10
-#define	  SOLO_AUDIO_EVOL(ch, value)		((value)<<((ch)%10))
-#define SOLO_AUDIO_STA				0x0D14
-
-/*
- * Watchdog configuration
- */
-#define SOLO_WATCHDOG				0x0be4
-#define SOLO_WATCHDOG_SET(status, sec)		(status << 8 | (sec & 0xff))
-
-#endif /* __SOLO6X10_REGISTERS_H */
diff --git a/drivers/staging/media/solo6x10/solo6x10-tw28.c b/drivers/staging/media/solo6x10/solo6x10-tw28.c
deleted file mode 100644
index edd0781ee4b51..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10-tw28.c
+++ /dev/null
@@ -1,871 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-
-#include "solo6x10.h"
-#include "solo6x10-tw28.h"
-
-#define DEFAULT_HDELAY_NTSC		(32 - 8)
-#define DEFAULT_HACTIVE_NTSC		(720 + 16)
-#define DEFAULT_VDELAY_NTSC		(7 - 2)
-#define DEFAULT_VACTIVE_NTSC		(240 + 4)
-
-#define DEFAULT_HDELAY_PAL		(32 + 4)
-#define DEFAULT_HACTIVE_PAL		(864-DEFAULT_HDELAY_PAL)
-#define DEFAULT_VDELAY_PAL		(6)
-#define DEFAULT_VACTIVE_PAL		(312-DEFAULT_VDELAY_PAL)
-
-
-static const u8 tbl_tw2864_ntsc_template[] = {
-	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
-	0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
-	0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
-	0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
-	0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
-	0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
-	0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
-	0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */
-	0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01,
-	0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */
-	0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
-	0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
-	0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
-	0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */
-	0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81,
-	0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
-	0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
-	0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
-	0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
-};
-
-static const u8 tbl_tw2864_pal_template[] = {
-	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */
-	0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
-	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */
-	0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
-	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */
-	0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
-	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */
-	0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
-	0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
-	0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
-	0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */
-	0x00, 0x28, 0x44, 0x44, 0xa0, 0x90, 0x5a, 0x01,
-	0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */
-	0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
-	0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
-	0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
-	0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */
-	0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81,
-	0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
-	0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
-	0x83, 0xb5, 0x09, 0x00, 0xa0, 0x00, 0x01, 0x20, /* 0xf0 */
-	0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
-};
-
-static const u8 tbl_tw2865_ntsc_template[] = {
-	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
-	0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
-	0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
-	0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-	0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
-	0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-	0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, /* 0x40 */
-	0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
-	0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
-	0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
-	0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
-	0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
-	0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
-	0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
-	0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, /* 0xa0 */
-	0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
-	0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
-	0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8,
-	0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
-	0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
-	0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
-	0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
-	0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
-	0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
-	0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
-	0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
-};
-
-static const u8 tbl_tw2865_pal_template[] = {
-	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */
-	0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
-	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */
-	0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
-	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */
-	0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
-	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */
-	0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
-	0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, /* 0x40 */
-	0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
-	0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
-	0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
-	0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
-	0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
-	0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
-	0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
-	0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, /* 0xa0 */
-	0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
-	0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
-	0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8,
-	0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
-	0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
-	0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
-	0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
-	0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
-	0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
-	0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, /* 0xf0 */
-	0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
-};
-
-#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
-
-static u8 tw_readbyte(struct solo_dev *solo_dev, int chip_id, u8 tw6x_off,
-		      u8 tw_off)
-{
-	if (is_tw286x(solo_dev, chip_id))
-		return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
-					 TW_CHIP_OFFSET_ADDR(chip_id),
-					 tw6x_off);
-	else
-		return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
-					 TW_CHIP_OFFSET_ADDR(chip_id),
-					 tw_off);
-}
-
-static void tw_writebyte(struct solo_dev *solo_dev, int chip_id,
-			 u8 tw6x_off, u8 tw_off, u8 val)
-{
-	if (is_tw286x(solo_dev, chip_id))
-		solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
-				   TW_CHIP_OFFSET_ADDR(chip_id),
-				   tw6x_off, val);
-	else
-		solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
-				   TW_CHIP_OFFSET_ADDR(chip_id),
-				   tw_off, val);
-}
-
-static void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off,
-				u8 val)
-{
-	int i;
-
-	for (i = 0; i < 5; i++) {
-		u8 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, addr, off);
-
-		if (rval == val)
-			return;
-
-		solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, addr, off, val);
-		msleep_interruptible(1);
-	}
-
-/*	printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n", */
-/*		addr, off, val); */
-}
-
-static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr)
-{
-	u8 tbl_tw2865_common[256];
-	int i;
-
-	if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL)
-		memcpy(tbl_tw2865_common, tbl_tw2865_pal_template,
-		       sizeof(tbl_tw2865_common));
-	else
-		memcpy(tbl_tw2865_common, tbl_tw2865_ntsc_template,
-		       sizeof(tbl_tw2865_common));
-
-	/* ALINK Mode */
-	if (solo_dev->nr_chans == 4) {
-		tbl_tw2865_common[0xd2] = 0x01;
-		tbl_tw2865_common[0xcf] = 0x00;
-	} else if (solo_dev->nr_chans == 8) {
-		tbl_tw2865_common[0xd2] = 0x02;
-		if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-			tbl_tw2865_common[0xcf] = 0x80;
-	} else if (solo_dev->nr_chans == 16) {
-		tbl_tw2865_common[0xd2] = 0x03;
-		if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-			tbl_tw2865_common[0xcf] = 0x83;
-		else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
-			tbl_tw2865_common[0xcf] = 0x83;
-		else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
-			tbl_tw2865_common[0xcf] = 0x80;
-	}
-
-	for (i = 0; i < 0xff; i++) {
-		/* Skip read only registers */
-		switch (i) {
-		case 0xb8 ... 0xc1:
-		case 0xc4 ... 0xc7:
-		case 0xfd:
-			continue;
-		}
-		switch (i & ~0x30) {
-		case 0x00:
-		case 0x0c ... 0x0d:
-			continue;
-		}
-
-		tw_write_and_verify(solo_dev, dev_addr, i,
-				    tbl_tw2865_common[i]);
-	}
-
-	return 0;
-}
-
-static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr)
-{
-	u8 tbl_tw2864_common[256];
-	int i;
-
-	if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL)
-		memcpy(tbl_tw2864_common, tbl_tw2864_pal_template,
-		       sizeof(tbl_tw2864_common));
-	else
-		memcpy(tbl_tw2864_common, tbl_tw2864_ntsc_template,
-		       sizeof(tbl_tw2864_common));
-
-	if (solo_dev->tw2865 == 0) {
-		/* IRQ Mode */
-		if (solo_dev->nr_chans == 4) {
-			tbl_tw2864_common[0xd2] = 0x01;
-			tbl_tw2864_common[0xcf] = 0x00;
-		} else if (solo_dev->nr_chans == 8) {
-			tbl_tw2864_common[0xd2] = 0x02;
-			if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
-				tbl_tw2864_common[0xcf] = 0x43;
-			else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-				tbl_tw2864_common[0xcf] = 0x40;
-		} else if (solo_dev->nr_chans == 16) {
-			tbl_tw2864_common[0xd2] = 0x03;
-			if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
-				tbl_tw2864_common[0xcf] = 0x43;
-			else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-				tbl_tw2864_common[0xcf] = 0x43;
-			else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
-				tbl_tw2864_common[0xcf] = 0x43;
-			else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
-				tbl_tw2864_common[0xcf] = 0x40;
-		}
-	} else {
-		/* ALINK Mode. Assumes that the first tw28xx is a
-		 * 2865 and these are in cascade. */
-		for (i = 0; i <= 4; i++)
-			tbl_tw2864_common[0x08 | i << 4] = 0x12;
-
-		if (solo_dev->nr_chans == 8) {
-			tbl_tw2864_common[0xd2] = 0x02;
-			if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-				tbl_tw2864_common[0xcf] = 0x80;
-		} else if (solo_dev->nr_chans == 16) {
-			tbl_tw2864_common[0xd2] = 0x03;
-			if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-				tbl_tw2864_common[0xcf] = 0x83;
-			else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
-				tbl_tw2864_common[0xcf] = 0x83;
-			else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
-				tbl_tw2864_common[0xcf] = 0x80;
-		}
-	}
-
-	for (i = 0; i < 0xff; i++) {
-		/* Skip read only registers */
-		switch (i) {
-		case 0xb8 ... 0xc1:
-		case 0xfd:
-			continue;
-		}
-		switch (i & ~0x30) {
-		case 0x00:
-		case 0x0c:
-		case 0x0d:
-			continue;
-		}
-
-		tw_write_and_verify(solo_dev, dev_addr, i,
-				    tbl_tw2864_common[i]);
-	}
-
-	return 0;
-}
-
-static int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr)
-{
-	u8 tbl_ntsc_tw2815_common[] = {
-		0x00, 0xc8, 0x20, 0xd0, 0x06, 0xf0, 0x08, 0x80,
-		0x80, 0x80, 0x80, 0x02, 0x06, 0x00, 0x11,
-	};
-
-	u8 tbl_pal_tw2815_common[] = {
-		0x00, 0x88, 0x20, 0xd0, 0x05, 0x20, 0x28, 0x80,
-		0x80, 0x80, 0x80, 0x82, 0x06, 0x00, 0x11,
-	};
-
-	u8 tbl_tw2815_sfr[] = {
-		0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, /* 0x00 */
-		0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00,
-		0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, /* 0x10 */
-		0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00,
-		0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, /* 0x20 */
-		0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88,
-		0x88, 0x11, 0x00, 0x88, 0x88, 0x00,		/* 0x30 */
-	};
-	u8 *tbl_tw2815_common;
-	int i;
-	int ch;
-
-	tbl_ntsc_tw2815_common[0x06] = 0;
-
-	/* Horizontal Delay Control */
-	tbl_ntsc_tw2815_common[0x02] = DEFAULT_HDELAY_NTSC & 0xff;
-	tbl_ntsc_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_NTSC >> 8);
-
-	/* Horizontal Active Control */
-	tbl_ntsc_tw2815_common[0x03] = DEFAULT_HACTIVE_NTSC & 0xff;
-	tbl_ntsc_tw2815_common[0x06] |=
-		((0x03 & (DEFAULT_HACTIVE_NTSC >> 8)) << 2);
-
-	/* Vertical Delay Control */
-	tbl_ntsc_tw2815_common[0x04] = DEFAULT_VDELAY_NTSC & 0xff;
-	tbl_ntsc_tw2815_common[0x06] |=
-		((0x01 & (DEFAULT_VDELAY_NTSC >> 8)) << 4);
-
-	/* Vertical Active Control */
-	tbl_ntsc_tw2815_common[0x05] = DEFAULT_VACTIVE_NTSC & 0xff;
-	tbl_ntsc_tw2815_common[0x06] |=
-		((0x01 & (DEFAULT_VACTIVE_NTSC >> 8)) << 5);
-
-	tbl_pal_tw2815_common[0x06] = 0;
-
-	/* Horizontal Delay Control */
-	tbl_pal_tw2815_common[0x02] = DEFAULT_HDELAY_PAL & 0xff;
-	tbl_pal_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_PAL >> 8);
-
-	/* Horizontal Active Control */
-	tbl_pal_tw2815_common[0x03] = DEFAULT_HACTIVE_PAL & 0xff;
-	tbl_pal_tw2815_common[0x06] |=
-		((0x03 & (DEFAULT_HACTIVE_PAL >> 8)) << 2);
-
-	/* Vertical Delay Control */
-	tbl_pal_tw2815_common[0x04] = DEFAULT_VDELAY_PAL & 0xff;
-	tbl_pal_tw2815_common[0x06] |=
-		((0x01 & (DEFAULT_VDELAY_PAL >> 8)) << 4);
-
-	/* Vertical Active Control */
-	tbl_pal_tw2815_common[0x05] = DEFAULT_VACTIVE_PAL & 0xff;
-	tbl_pal_tw2815_common[0x06] |=
-		((0x01 & (DEFAULT_VACTIVE_PAL >> 8)) << 5);
-
-	tbl_tw2815_common =
-	    (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) ?
-	     tbl_ntsc_tw2815_common : tbl_pal_tw2815_common;
-
-	/* Dual ITU-R BT.656 format */
-	tbl_tw2815_common[0x0d] |= 0x04;
-
-	/* Audio configuration */
-	tbl_tw2815_sfr[0x62 - 0x40] &= ~(3 << 6);
-
-	if (solo_dev->nr_chans == 4) {
-		tbl_tw2815_sfr[0x63 - 0x40] |= 1;
-		tbl_tw2815_sfr[0x62 - 0x40] |= 3 << 6;
-	} else if (solo_dev->nr_chans == 8) {
-		tbl_tw2815_sfr[0x63 - 0x40] |= 2;
-		if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
-			tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
-		else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-			tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
-	} else if (solo_dev->nr_chans == 16) {
-		tbl_tw2815_sfr[0x63 - 0x40] |= 3;
-		if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
-			tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
-		else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-			tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
-		else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
-			tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
-		else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
-			tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
-	}
-
-	/* Output mode of R_ADATM pin (0 mixing, 1 record) */
-	/* tbl_tw2815_sfr[0x63 - 0x40] |= 0 << 2; */
-
-	/* 8KHz, used to be 16KHz, but changed for remote client compat */
-	tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 2;
-	tbl_tw2815_sfr[0x6c - 0x40] |= 0 << 2;
-
-	/* Playback of right channel */
-	tbl_tw2815_sfr[0x6c - 0x40] |= 1 << 5;
-
-	/* Reserved value (XXX ??) */
-	tbl_tw2815_sfr[0x5c - 0x40] |= 1 << 5;
-
-	/* Analog output gain and mix ratio playback on full */
-	tbl_tw2815_sfr[0x70 - 0x40] |= 0xff;
-	/* Select playback audio and mute all except */
-	tbl_tw2815_sfr[0x71 - 0x40] |= 0x10;
-	tbl_tw2815_sfr[0x6d - 0x40] |= 0x0f;
-
-	/* End of audio configuration */
-
-	for (ch = 0; ch < 4; ch++) {
-		tbl_tw2815_common[0x0d] &= ~3;
-		switch (ch) {
-		case 0:
-			tbl_tw2815_common[0x0d] |= 0x21;
-			break;
-		case 1:
-			tbl_tw2815_common[0x0d] |= 0x20;
-			break;
-		case 2:
-			tbl_tw2815_common[0x0d] |= 0x23;
-			break;
-		case 3:
-			tbl_tw2815_common[0x0d] |= 0x22;
-			break;
-		}
-
-		for (i = 0; i < 0x0f; i++) {
-			if (i == 0x00)
-				continue;	/* read-only */
-			solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
-					   dev_addr, (ch * 0x10) + i,
-					   tbl_tw2815_common[i]);
-		}
-	}
-
-	for (i = 0x40; i < 0x76; i++) {
-		/* Skip read-only and nop registers */
-		if (i == 0x40 || i == 0x59 || i == 0x5a ||
-		    i == 0x5d || i == 0x5e || i == 0x5f)
-			continue;
-
-		solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, dev_addr, i,
-				       tbl_tw2815_sfr[i - 0x40]);
-	}
-
-	return 0;
-}
-
-#define FIRST_ACTIVE_LINE	0x0008
-#define LAST_ACTIVE_LINE	0x0102
-
-static void saa712x_write_regs(struct solo_dev *dev, const uint8_t *vals,
-		int start, int n)
-{
-	for (; start < n; start++, vals++) {
-		/* Skip read-only registers */
-		switch (start) {
-		/* case 0x00 ... 0x25: */
-		case 0x2e ... 0x37:
-		case 0x60:
-		case 0x7d:
-			continue;
-		}
-		solo_i2c_writebyte(dev, SOLO_I2C_SAA, 0x46, start, *vals);
-	}
-}
-
-#define SAA712x_reg7c (0x80 | ((LAST_ACTIVE_LINE & 0x100) >> 2) \
-		| ((FIRST_ACTIVE_LINE & 0x100) >> 4))
-
-static void saa712x_setup(struct solo_dev *dev)
-{
-	const int reg_start = 0x26;
-	const uint8_t saa7128_regs_ntsc[] = {
-	/* :0x26 */
-		0x0d, 0x00,
-	/* :0x28 */
-		0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f,
-	/* :0x2e XXX: read-only */
-		0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	/* :0x38 */
-		0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
-	/* :0x40 */
-		0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
-		0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
-	/* :0x50 */
-		0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
-		0x02, 0x80, 0x71, 0x77, 0xa7, 0x67, 0x66, 0x2e,
-	/* :0x60 */
-		0x7b, 0x11, 0x4f, 0x1f, 0x7c, 0xf0, 0x21, 0x77,
-		0x41, 0x88, 0x41, 0x52, 0xed, 0x10, 0x10, 0x00,
-	/* :0x70 */
-		0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
-		0x00, 0x00, FIRST_ACTIVE_LINE, LAST_ACTIVE_LINE & 0xff,
-		SAA712x_reg7c, 0x00, 0xff, 0xff,
-	}, saa7128_regs_pal[] = {
-	/* :0x26 */
-		0x0d, 0x00,
-	/* :0x28 */
-		0xe1, 0x1d, 0x75, 0x3f, 0x06, 0x3f,
-	/* :0x2e XXX: read-only */
-		0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	/* :0x38 */
-		0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
-	/* :0x40 */
-		0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
-		0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
-	/* :0x50 */
-		0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
-		0x02, 0x80, 0x0f, 0x77, 0xa7, 0x67, 0x66, 0x2e,
-	/* :0x60 */
-		0x7b, 0x02, 0x35, 0xcb, 0x8a, 0x09, 0x2a, 0x77,
-		0x41, 0x88, 0x41, 0x52, 0xf1, 0x10, 0x20, 0x00,
-	/* :0x70 */
-		0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
-		0x00, 0x00, 0x12, 0x30,
-		SAA712x_reg7c | 0x40, 0x00, 0xff, 0xff,
-	};
-
-	if (dev->video_type == SOLO_VO_FMT_TYPE_PAL)
-		saa712x_write_regs(dev, saa7128_regs_pal, reg_start,
-				sizeof(saa7128_regs_pal));
-	else
-		saa712x_write_regs(dev, saa7128_regs_ntsc, reg_start,
-				sizeof(saa7128_regs_ntsc));
-}
-
-int solo_tw28_init(struct solo_dev *solo_dev)
-{
-	int i;
-	u8 value;
-
-	solo_dev->tw28_cnt = 0;
-
-	/* Detect techwell chip type(s) */
-	for (i = 0; i < solo_dev->nr_chans / 4; i++) {
-		value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
-					  TW_CHIP_OFFSET_ADDR(i), 0xFF);
-
-		switch (value >> 3) {
-		case 0x18:
-			solo_dev->tw2865 |= 1 << i;
-			solo_dev->tw28_cnt++;
-			break;
-		case 0x0c:
-			solo_dev->tw2864 |= 1 << i;
-			solo_dev->tw28_cnt++;
-			break;
-		default:
-			value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
-						  TW_CHIP_OFFSET_ADDR(i),
-						  0x59);
-			if ((value >> 3) == 0x04) {
-				solo_dev->tw2815 |= 1 << i;
-				solo_dev->tw28_cnt++;
-			}
-		}
-	}
-
-	if (solo_dev->tw28_cnt != (solo_dev->nr_chans >> 2)) {
-		dev_err(&solo_dev->pdev->dev,
-			"Could not initialize any techwell chips\n");
-		return -EINVAL;
-	}
-
-	saa712x_setup(solo_dev);
-
-	for (i = 0; i < solo_dev->tw28_cnt; i++) {
-		if ((solo_dev->tw2865 & (1 << i)))
-			tw2865_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
-		else if ((solo_dev->tw2864 & (1 << i)))
-			tw2864_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
-		else
-			tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
-	}
-
-	return 0;
-}
-
-/*
- * We accessed the video status signal in the Techwell chip through
- * iic/i2c because the video status reported by register REG_VI_STATUS1
- * (address 0x012C) of the SOLO6010 chip doesn't give the correct video
- * status signal values.
- */
-int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch)
-{
-	u8 val, chip_num;
-
-	/* Get the right chip and on-chip channel */
-	chip_num = ch / 4;
-	ch %= 4;
-
-	val = tw_readbyte(solo_dev, chip_num, TW286x_AV_STAT_ADDR,
-			  TW_AV_STAT_ADDR) & 0x0f;
-
-	return val & (1 << ch) ? 1 : 0;
-}
-
-#if 0
-/* Status of audio from up to 4 techwell chips are combined into 1 variable.
- * See techwell datasheet for details. */
-u16 tw28_get_audio_status(struct solo_dev *solo_dev)
-{
-	u8 val;
-	u16 status = 0;
-	int i;
-
-	for (i = 0; i < solo_dev->tw28_cnt; i++) {
-		val = (tw_readbyte(solo_dev, i, TW286x_AV_STAT_ADDR,
-				   TW_AV_STAT_ADDR) & 0xf0) >> 4;
-		status |= val << (i * 4);
-	}
-
-	return status;
-}
-#endif
-
-bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch)
-{
-	return is_tw286x(solo_dev, ch / 4);
-}
-
-int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
-		      s32 val)
-{
-	char sval;
-	u8 chip_num;
-
-	/* Get the right chip and on-chip channel */
-	chip_num = ch / 4;
-	ch %= 4;
-
-	if (val > 255 || val < 0)
-		return -ERANGE;
-
-	switch (ctrl) {
-	case V4L2_CID_SHARPNESS:
-		/* Only 286x has sharpness */
-		if (is_tw286x(solo_dev, chip_num)) {
-			u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
-						 TW_CHIP_OFFSET_ADDR(chip_num),
-						 TW286x_SHARPNESS(chip_num));
-			v &= 0xf0;
-			v |= val;
-			solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
-					   TW_CHIP_OFFSET_ADDR(chip_num),
-					   TW286x_SHARPNESS(chip_num), v);
-		} else {
-			return -EINVAL;
-		}
-		break;
-
-	case V4L2_CID_HUE:
-		if (is_tw286x(solo_dev, chip_num))
-			sval = val - 128;
-		else
-			sval = (char)val;
-		tw_writebyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
-			     TW_HUE_ADDR(ch), sval);
-
-		break;
-
-	case V4L2_CID_SATURATION:
-		/* 286x chips have a U and V component for saturation */
-		if (is_tw286x(solo_dev, chip_num)) {
-			solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
-					   TW_CHIP_OFFSET_ADDR(chip_num),
-					   TW286x_SATURATIONU_ADDR(ch), val);
-		}
-		tw_writebyte(solo_dev, chip_num, TW286x_SATURATIONV_ADDR(ch),
-			     TW_SATURATION_ADDR(ch), val);
-
-		break;
-
-	case V4L2_CID_CONTRAST:
-		tw_writebyte(solo_dev, chip_num, TW286x_CONTRAST_ADDR(ch),
-			     TW_CONTRAST_ADDR(ch), val);
-		break;
-
-	case V4L2_CID_BRIGHTNESS:
-		if (is_tw286x(solo_dev, chip_num))
-			sval = val - 128;
-		else
-			sval = (char)val;
-		tw_writebyte(solo_dev, chip_num, TW286x_BRIGHTNESS_ADDR(ch),
-			     TW_BRIGHTNESS_ADDR(ch), sval);
-
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
-		      s32 *val)
-{
-	u8 rval, chip_num;
-
-	/* Get the right chip and on-chip channel */
-	chip_num = ch / 4;
-	ch %= 4;
-
-	switch (ctrl) {
-	case V4L2_CID_SHARPNESS:
-		/* Only 286x has sharpness */
-		if (is_tw286x(solo_dev, chip_num)) {
-			rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
-						 TW_CHIP_OFFSET_ADDR(chip_num),
-						 TW286x_SHARPNESS(chip_num));
-			*val = rval & 0x0f;
-		} else
-			*val = 0;
-		break;
-	case V4L2_CID_HUE:
-		rval = tw_readbyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
-				   TW_HUE_ADDR(ch));
-		if (is_tw286x(solo_dev, chip_num))
-			*val = (s32)((char)rval) + 128;
-		else
-			*val = rval;
-		break;
-	case V4L2_CID_SATURATION:
-		*val = tw_readbyte(solo_dev, chip_num,
-				   TW286x_SATURATIONU_ADDR(ch),
-				   TW_SATURATION_ADDR(ch));
-		break;
-	case V4L2_CID_CONTRAST:
-		*val = tw_readbyte(solo_dev, chip_num,
-				   TW286x_CONTRAST_ADDR(ch),
-				   TW_CONTRAST_ADDR(ch));
-		break;
-	case V4L2_CID_BRIGHTNESS:
-		rval = tw_readbyte(solo_dev, chip_num,
-				   TW286x_BRIGHTNESS_ADDR(ch),
-				   TW_BRIGHTNESS_ADDR(ch));
-		if (is_tw286x(solo_dev, chip_num))
-			*val = (s32)((char)rval) + 128;
-		else
-			*val = rval;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-#if 0
-/*
- * For audio output volume, the output channel is only 1. In this case we
- * don't need to offset TW_CHIP_OFFSET_ADDR. The TW_CHIP_OFFSET_ADDR used
- * is the base address of the techwell chip.
- */
-void tw2815_Set_AudioOutVol(struct solo_dev *solo_dev, unsigned int u_val)
-{
-	unsigned int val;
-	unsigned int chip_num;
-
-	chip_num = (solo_dev->nr_chans - 1) / 4;
-
-	val = tw_readbyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
-			  TW_AUDIO_OUTPUT_VOL_ADDR);
-
-	u_val = (val & 0x0f) | (u_val << 4);
-
-	tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
-		     TW_AUDIO_OUTPUT_VOL_ADDR, u_val);
-}
-#endif
-
-u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch)
-{
-	u8 val;
-	u8 chip_num;
-
-	/* Get the right chip and on-chip channel */
-	chip_num = ch / 4;
-	ch %= 4;
-
-	val = tw_readbyte(solo_dev, chip_num,
-			  TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
-			  TW_AUDIO_INPUT_GAIN_ADDR(ch));
-
-	return (ch % 2) ? (val >> 4) : (val & 0x0f);
-}
-
-void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val)
-{
-	u8 old_val;
-	u8 chip_num;
-
-	/* Get the right chip and on-chip channel */
-	chip_num = ch / 4;
-	ch %= 4;
-
-	old_val = tw_readbyte(solo_dev, chip_num,
-			      TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
-			      TW_AUDIO_INPUT_GAIN_ADDR(ch));
-
-	val = (old_val & ((ch % 2) ? 0x0f : 0xf0)) |
-		((ch % 2) ? (val << 4) : val);
-
-	tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
-		     TW_AUDIO_INPUT_GAIN_ADDR(ch), val);
-}
diff --git a/drivers/staging/media/solo6x10/solo6x10-tw28.h b/drivers/staging/media/solo6x10/solo6x10-tw28.h
deleted file mode 100644
index 0966b45057a33..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10-tw28.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-#ifndef __SOLO6X10_TW28_H
-#define __SOLO6X10_TW28_H
-
-#include "solo6x10.h"
-
-#define TW_NUM_CHIP				4
-#define TW_BASE_ADDR				0x28
-#define TW_CHIP_OFFSET_ADDR(n)			(TW_BASE_ADDR + (n))
-
-/* tw2815 */
-#define TW_AV_STAT_ADDR				0x5a
-#define TW_HUE_ADDR(n)				(0x07 | ((n) << 4))
-#define TW_SATURATION_ADDR(n)			(0x08 | ((n) << 4))
-#define TW_CONTRAST_ADDR(n)			(0x09 | ((n) << 4))
-#define TW_BRIGHTNESS_ADDR(n)			(0x0a | ((n) << 4))
-#define TW_AUDIO_OUTPUT_VOL_ADDR		0x70
-#define TW_AUDIO_INPUT_GAIN_ADDR(n)		(0x60 + ((n > 1) ? 1 : 0))
-
-/* tw286x */
-#define TW286x_AV_STAT_ADDR			0xfd
-#define TW286x_HUE_ADDR(n)			(0x06 | ((n) << 4))
-#define TW286x_SATURATIONU_ADDR(n)		(0x04 | ((n) << 4))
-#define TW286x_SATURATIONV_ADDR(n)		(0x05 | ((n) << 4))
-#define TW286x_CONTRAST_ADDR(n)			(0x02 | ((n) << 4))
-#define TW286x_BRIGHTNESS_ADDR(n)		(0x01 | ((n) << 4))
-#define TW286x_SHARPNESS(n)			(0x03 | ((n) << 4))
-#define TW286x_AUDIO_OUTPUT_VOL_ADDR		0xdf
-#define TW286x_AUDIO_INPUT_GAIN_ADDR(n)		(0xD0 + ((n > 1) ? 1 : 0))
-
-int solo_tw28_init(struct solo_dev *solo_dev);
-
-int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val);
-int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 *val);
-bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch);
-
-u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch);
-void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val);
-int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch);
-
-#if 0
-unsigned int tw2815_get_audio_status(struct SOLO *solo);
-void tw2815_Set_AudioOutVol(struct SOLO *solo, unsigned int u_val);
-#endif
-
-#endif /* __SOLO6X10_TW28_H */
diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
deleted file mode 100644
index 2e07b497a37c5..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
+++ /dev/null
@@ -1,1434 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-event.h>
-#include <media/videobuf2-dma-sg.h>
-
-#include "solo6x10.h"
-#include "solo6x10-tw28.h"
-#include "solo6x10-jpeg.h"
-
-#define MIN_VID_BUFFERS		2
-#define FRAME_BUF_SIZE		(196 * 1024)
-#define MP4_QS			16
-#define DMA_ALIGN		4096
-
-/* 6010 M4V */
-static unsigned char vop_6010_ntsc_d1[] = {
-	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
-	0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40,
-	0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
-	0x1f, 0x4c, 0x58, 0x10, 0xf0, 0x71, 0x18, 0x3f,
-};
-
-static unsigned char vop_6010_ntsc_cif[] = {
-	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
-	0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40,
-	0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
-	0x1f, 0x4c, 0x2c, 0x10, 0x78, 0x51, 0x18, 0x3f,
-};
-
-static unsigned char vop_6010_pal_d1[] = {
-	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
-	0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40,
-	0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
-	0x1f, 0x4c, 0x58, 0x11, 0x20, 0x71, 0x18, 0x3f,
-};
-
-static unsigned char vop_6010_pal_cif[] = {
-	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
-	0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40,
-	0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
-	0x1f, 0x4c, 0x2c, 0x10, 0x90, 0x51, 0x18, 0x3f,
-};
-
-/* 6110 h.264 */
-static unsigned char vop_6110_ntsc_d1[] = {
-	0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
-	0x9a, 0x74, 0x05, 0x81, 0xec, 0x80, 0x00, 0x00,
-	0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00,
-};
-
-static unsigned char vop_6110_ntsc_cif[] = {
-	0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
-	0x9a, 0x74, 0x0b, 0x0f, 0xc8, 0x00, 0x00, 0x00,
-	0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00,
-};
-
-static unsigned char vop_6110_pal_d1[] = {
-	0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
-	0x9a, 0x74, 0x05, 0x80, 0x93, 0x20, 0x00, 0x00,
-	0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00,
-};
-
-static unsigned char vop_6110_pal_cif[] = {
-	0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
-	0x9a, 0x74, 0x0b, 0x04, 0xb2, 0x00, 0x00, 0x00,
-	0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00,
-};
-
-typedef __le32 vop_header[16];
-
-struct solo_enc_buf {
-	enum solo_enc_types	type;
-	const vop_header	*vh;
-	int			motion;
-};
-
-static int solo_is_motion_on(struct solo_enc_dev *solo_enc)
-{
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-	return (solo_dev->motion_mask >> solo_enc->ch) & 1;
-}
-
-static int solo_motion_detected(struct solo_enc_dev *solo_enc)
-{
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-	unsigned long flags;
-	u32 ch_mask = 1 << solo_enc->ch;
-	int ret = 0;
-
-	spin_lock_irqsave(&solo_enc->motion_lock, flags);
-	if (solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS) & ch_mask) {
-		solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, ch_mask);
-		ret = 1;
-	}
-	spin_unlock_irqrestore(&solo_enc->motion_lock, flags);
-
-	return ret;
-}
-
-static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on)
-{
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-	u32 mask = 1 << solo_enc->ch;
-	unsigned long flags;
-
-	spin_lock_irqsave(&solo_enc->motion_lock, flags);
-
-	if (on)
-		solo_dev->motion_mask |= mask;
-	else
-		solo_dev->motion_mask &= ~mask;
-
-	solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, mask);
-
-	solo_reg_write(solo_dev, SOLO_VI_MOT_ADR,
-		       SOLO_VI_MOTION_EN(solo_dev->motion_mask) |
-		       (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
-
-	spin_unlock_irqrestore(&solo_enc->motion_lock, flags);
-}
-
-void solo_update_mode(struct solo_enc_dev *solo_enc)
-{
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-	int vop_len;
-	unsigned char *vop;
-
-	solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0;
-	solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1);
-
-	if (solo_enc->mode == SOLO_ENC_MODE_CIF) {
-		solo_enc->width = solo_dev->video_hsize >> 1;
-		solo_enc->height = solo_dev->video_vsize;
-		if (solo_dev->type == SOLO_DEV_6110) {
-			if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
-				vop = vop_6110_ntsc_cif;
-				vop_len = sizeof(vop_6110_ntsc_cif);
-			} else {
-				vop = vop_6110_pal_cif;
-				vop_len = sizeof(vop_6110_pal_cif);
-			}
-		} else {
-			if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
-				vop = vop_6010_ntsc_cif;
-				vop_len = sizeof(vop_6010_ntsc_cif);
-			} else {
-				vop = vop_6010_pal_cif;
-				vop_len = sizeof(vop_6010_pal_cif);
-			}
-		}
-	} else {
-		solo_enc->width = solo_dev->video_hsize;
-		solo_enc->height = solo_dev->video_vsize << 1;
-		solo_enc->bw_weight <<= 2;
-		if (solo_dev->type == SOLO_DEV_6110) {
-			if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
-				vop = vop_6110_ntsc_d1;
-				vop_len = sizeof(vop_6110_ntsc_d1);
-			} else {
-				vop = vop_6110_pal_d1;
-				vop_len = sizeof(vop_6110_pal_d1);
-			}
-		} else {
-			if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
-				vop = vop_6010_ntsc_d1;
-				vop_len = sizeof(vop_6010_ntsc_d1);
-			} else {
-				vop = vop_6010_pal_d1;
-				vop_len = sizeof(vop_6010_pal_d1);
-			}
-		}
-	}
-
-	memcpy(solo_enc->vop, vop, vop_len);
-
-	/* Some fixups for 6010/M4V */
-	if (solo_dev->type == SOLO_DEV_6010) {
-		u16 fps = solo_dev->fps * 1000;
-		u16 interval = solo_enc->interval * 1000;
-
-		vop = solo_enc->vop;
-
-		/* Frame rate and interval */
-		vop[22] = fps >> 4;
-		vop[23] = ((fps << 4) & 0xf0) | 0x0c
-			| ((interval >> 13) & 0x3);
-		vop[24] = (interval >> 5) & 0xff;
-		vop[25] = ((interval << 3) & 0xf8) | 0x04;
-	}
-
-	solo_enc->vop_len = vop_len;
-
-	/* Now handle the jpeg header */
-	vop = solo_enc->jpeg_header;
-	vop[SOF0_START + 5] = 0xff & (solo_enc->height >> 8);
-	vop[SOF0_START + 6] = 0xff & solo_enc->height;
-	vop[SOF0_START + 7] = 0xff & (solo_enc->width >> 8);
-	vop[SOF0_START + 8] = 0xff & solo_enc->width;
-
-	memcpy(vop + DQT_START,
-	       jpeg_dqt[solo_g_jpeg_qp(solo_dev, solo_enc->ch)], DQT_LEN);
-}
-
-static int solo_enc_on(struct solo_enc_dev *solo_enc)
-{
-	u8 ch = solo_enc->ch;
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-	u8 interval;
-
-	solo_update_mode(solo_enc);
-
-	/* Make sure to do a bandwidth check */
-	if (solo_enc->bw_weight > solo_dev->enc_bw_remain)
-		return -EBUSY;
-	solo_enc->sequence = 0;
-	solo_enc->motion_last_state = false;
-	solo_enc->frames_since_last_motion = 0;
-	solo_dev->enc_bw_remain -= solo_enc->bw_weight;
-
-	if (solo_enc->type == SOLO_ENC_TYPE_EXT)
-		solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1);
-
-	/* Disable all encoding for this channel */
-	solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0);
-
-	/* Common for both std and ext encoding */
-	solo_reg_write(solo_dev, SOLO_VE_CH_INTL(ch),
-		       solo_enc->interlaced ? 1 : 0);
-
-	if (solo_enc->interlaced)
-		interval = solo_enc->interval - 1;
-	else
-		interval = solo_enc->interval;
-
-	/* Standard encoding only */
-	solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), solo_enc->gop);
-	solo_reg_write(solo_dev, SOLO_VE_CH_QP(ch), solo_enc->qp);
-	solo_reg_write(solo_dev, SOLO_CAP_CH_INTV(ch), interval);
-
-	/* Extended encoding only */
-	solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(ch), solo_enc->gop);
-	solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(ch), solo_enc->qp);
-	solo_reg_write(solo_dev, SOLO_CAP_CH_INTV_E(ch), interval);
-
-	/* Enables the standard encoder */
-	solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode);
-
-	return 0;
-}
-
-static void solo_enc_off(struct solo_enc_dev *solo_enc)
-{
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-	solo_dev->enc_bw_remain += solo_enc->bw_weight;
-
-	solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0);
-	solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0);
-}
-
-static int enc_get_mpeg_dma(struct solo_dev *solo_dev, dma_addr_t dma,
-			      unsigned int off, unsigned int size)
-{
-	int ret;
-
-	if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
-		return -EINVAL;
-
-	/* Single shot */
-	if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) {
-		return solo_p2m_dma_t(solo_dev, 0, dma,
-				      SOLO_MP4E_EXT_ADDR(solo_dev) + off, size,
-				      0, 0);
-	}
-
-	/* Buffer wrap */
-	ret = solo_p2m_dma_t(solo_dev, 0, dma,
-			     SOLO_MP4E_EXT_ADDR(solo_dev) + off,
-			     SOLO_MP4E_EXT_SIZE(solo_dev) - off, 0, 0);
-
-	if (!ret) {
-		ret = solo_p2m_dma_t(solo_dev, 0,
-			     dma + SOLO_MP4E_EXT_SIZE(solo_dev) - off,
-			     SOLO_MP4E_EXT_ADDR(solo_dev),
-			     size + off - SOLO_MP4E_EXT_SIZE(solo_dev), 0, 0);
-	}
-
-	return ret;
-}
-
-/* Build a descriptor queue out of an SG list and send it to the P2M for
- * processing. */
-static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip,
-			  struct sg_table *vbuf, int off, int size,
-			  unsigned int base, unsigned int base_size)
-{
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-	struct scatterlist *sg;
-	int i;
-	int ret;
-
-	if (WARN_ON_ONCE(size > FRAME_BUF_SIZE))
-		return -EINVAL;
-
-	solo_enc->desc_count = 1;
-
-	for_each_sg(vbuf->sgl, sg, vbuf->nents, i) {
-		struct solo_p2m_desc *desc;
-		dma_addr_t dma;
-		int len;
-		int left = base_size - off;
-
-		desc = &solo_enc->desc_items[solo_enc->desc_count++];
-		dma = sg_dma_address(sg);
-		len = sg_dma_len(sg);
-
-		/* We assume this is smaller than the scatter size */
-		BUG_ON(skip >= len);
-		if (skip) {
-			len -= skip;
-			dma += skip;
-			size -= skip;
-			skip = 0;
-		}
-
-		len = min(len, size);
-
-		if (len <= left) {
-			/* Single descriptor */
-			solo_p2m_fill_desc(desc, 0, dma, base + off,
-					   len, 0, 0);
-		} else {
-			/* Buffer wrap */
-			/* XXX: Do these as separate DMA requests, to avoid
-			   timeout errors triggered by awkwardly sized
-			   descriptors. See
-			   <https://github.com/bluecherrydvr/solo6x10/issues/8>
-			 */
-			ret = solo_p2m_dma_t(solo_dev, 0, dma, base + off,
-					     left, 0, 0);
-			if (ret)
-				return ret;
-
-			ret = solo_p2m_dma_t(solo_dev, 0, dma + left, base,
-					     len - left, 0, 0);
-			if (ret)
-				return ret;
-
-			solo_enc->desc_count--;
-		}
-
-		size -= len;
-		if (size <= 0)
-			break;
-
-		off += len;
-		if (off >= base_size)
-			off -= base_size;
-
-		/* Because we may use two descriptors per loop */
-		if (solo_enc->desc_count >= (solo_enc->desc_nelts - 1)) {
-			ret = solo_p2m_dma_desc(solo_dev, solo_enc->desc_items,
-						solo_enc->desc_dma,
-						solo_enc->desc_count - 1);
-			if (ret)
-				return ret;
-			solo_enc->desc_count = 1;
-		}
-	}
-
-	if (solo_enc->desc_count <= 1)
-		return 0;
-
-	return solo_p2m_dma_desc(solo_dev, solo_enc->desc_items,
-			solo_enc->desc_dma, solo_enc->desc_count - 1);
-}
-
-/* Extract values from VOP header - VE_STATUSxx */
-static inline int vop_interlaced(const vop_header *vh)
-{
-	return (__le32_to_cpu((*vh)[0]) >> 30) & 1;
-}
-
-static inline u8 vop_channel(const vop_header *vh)
-{
-	return (__le32_to_cpu((*vh)[0]) >> 24) & 0x1F;
-}
-
-static inline u8 vop_type(const vop_header *vh)
-{
-	return (__le32_to_cpu((*vh)[0]) >> 22) & 3;
-}
-
-static inline u32 vop_mpeg_size(const vop_header *vh)
-{
-	return __le32_to_cpu((*vh)[0]) & 0xFFFFF;
-}
-
-static inline u8 vop_hsize(const vop_header *vh)
-{
-	return (__le32_to_cpu((*vh)[1]) >> 8) & 0xFF;
-}
-
-static inline u8 vop_vsize(const vop_header *vh)
-{
-	return __le32_to_cpu((*vh)[1]) & 0xFF;
-}
-
-static inline u32 vop_mpeg_offset(const vop_header *vh)
-{
-	return __le32_to_cpu((*vh)[2]);
-}
-
-static inline u32 vop_jpeg_offset(const vop_header *vh)
-{
-	return __le32_to_cpu((*vh)[3]);
-}
-
-static inline u32 vop_jpeg_size(const vop_header *vh)
-{
-	return __le32_to_cpu((*vh)[4]) & 0xFFFFF;
-}
-
-static inline u32 vop_sec(const vop_header *vh)
-{
-	return __le32_to_cpu((*vh)[5]);
-}
-
-static inline u32 vop_usec(const vop_header *vh)
-{
-	return __le32_to_cpu((*vh)[6]);
-}
-
-static int solo_fill_jpeg(struct solo_enc_dev *solo_enc,
-			  struct vb2_buffer *vb, const vop_header *vh)
-{
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-	struct sg_table *vbuf = vb2_dma_sg_plane_desc(vb, 0);
-	int frame_size;
-	int ret;
-
-	vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
-
-	if (vb2_plane_size(vb, 0) < vop_jpeg_size(vh) + solo_enc->jpeg_len)
-		return -EIO;
-
-	frame_size = ALIGN(vop_jpeg_size(vh) + solo_enc->jpeg_len, DMA_ALIGN);
-	vb2_set_plane_payload(vb, 0, vop_jpeg_size(vh) + solo_enc->jpeg_len);
-
-	/* may discard all previous data in vbuf->sgl */
-	if (!dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
-			DMA_FROM_DEVICE))
-		return -ENOMEM;
-	ret = solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf,
-			     vop_jpeg_offset(vh) - SOLO_JPEG_EXT_ADDR(solo_dev),
-			     frame_size, SOLO_JPEG_EXT_ADDR(solo_dev),
-			     SOLO_JPEG_EXT_SIZE(solo_dev));
-	dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
-			DMA_FROM_DEVICE);
-
-	/* add the header only after dma_unmap_sg() */
-	sg_copy_from_buffer(vbuf->sgl, vbuf->nents,
-			    solo_enc->jpeg_header, solo_enc->jpeg_len);
-
-	return ret;
-}
-
-static int solo_fill_mpeg(struct solo_enc_dev *solo_enc,
-		struct vb2_buffer *vb, const vop_header *vh)
-{
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-	struct sg_table *vbuf = vb2_dma_sg_plane_desc(vb, 0);
-	int frame_off, frame_size;
-	int skip = 0;
-	int ret;
-
-	if (vb2_plane_size(vb, 0) < vop_mpeg_size(vh))
-		return -EIO;
-
-	/* If this is a key frame, add extra header */
-	vb->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME |
-		V4L2_BUF_FLAG_BFRAME);
-	if (!vop_type(vh)) {
-		skip = solo_enc->vop_len;
-		vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
-		vb2_set_plane_payload(vb, 0, vop_mpeg_size(vh) +
-			solo_enc->vop_len);
-	} else {
-		vb->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
-		vb2_set_plane_payload(vb, 0, vop_mpeg_size(vh));
-	}
-
-	/* Now get the actual mpeg payload */
-	frame_off = (vop_mpeg_offset(vh) - SOLO_MP4E_EXT_ADDR(solo_dev) +
-		sizeof(*vh)) % SOLO_MP4E_EXT_SIZE(solo_dev);
-	frame_size = ALIGN(vop_mpeg_size(vh) + skip, DMA_ALIGN);
-
-	/* may discard all previous data in vbuf->sgl */
-	if (!dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
-			DMA_FROM_DEVICE))
-		return -ENOMEM;
-	ret = solo_send_desc(solo_enc, skip, vbuf, frame_off, frame_size,
-			SOLO_MP4E_EXT_ADDR(solo_dev),
-			SOLO_MP4E_EXT_SIZE(solo_dev));
-	dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
-			DMA_FROM_DEVICE);
-
-	/* add the header only after dma_unmap_sg() */
-	if (!vop_type(vh))
-		sg_copy_from_buffer(vbuf->sgl, vbuf->nents,
-				    solo_enc->vop, solo_enc->vop_len);
-	return ret;
-}
-
-static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
-			    struct vb2_buffer *vb, struct solo_enc_buf *enc_buf)
-{
-	const vop_header *vh = enc_buf->vh;
-	int ret;
-
-	switch (solo_enc->fmt) {
-	case V4L2_PIX_FMT_MPEG4:
-	case V4L2_PIX_FMT_H264:
-		ret = solo_fill_mpeg(solo_enc, vb, vh);
-		break;
-	default: /* V4L2_PIX_FMT_MJPEG */
-		ret = solo_fill_jpeg(solo_enc, vb, vh);
-		break;
-	}
-
-	if (!ret) {
-		bool send_event = false;
-
-		vb->v4l2_buf.sequence = solo_enc->sequence++;
-		vb->v4l2_buf.timestamp.tv_sec = vop_sec(vh);
-		vb->v4l2_buf.timestamp.tv_usec = vop_usec(vh);
-
-		/* Check for motion flags */
-		if (solo_is_motion_on(solo_enc)) {
-			/* It takes a few frames for the hardware to detect
-			 * motion. Once it does it clears the motion detection
-			 * register and it takes again a few frames before
-			 * motion is seen. This means in practice that when the
-			 * motion field is 1, it will go back to 0 for the next
-			 * frame. This leads to motion detection event being
-			 * sent all the time, which is not what we want.
-			 * Instead wait a few frames before deciding that the
-			 * motion has halted. After some experimentation it
-			 * turns out that waiting for 5 frames works well.
-			 */
-			if (enc_buf->motion == 0 &&
-			    solo_enc->motion_last_state &&
-			    solo_enc->frames_since_last_motion++ > 5)
-				send_event = true;
-			else if (enc_buf->motion) {
-				solo_enc->frames_since_last_motion = 0;
-				send_event = !solo_enc->motion_last_state;
-			}
-		}
-
-		if (send_event) {
-			struct v4l2_event ev = {
-				.type = V4L2_EVENT_MOTION_DET,
-				.u.motion_det = {
-					.flags = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ,
-					.frame_sequence = vb->v4l2_buf.sequence,
-					.region_mask = enc_buf->motion ? 1 : 0,
-				},
-			};
-
-			solo_enc->motion_last_state = enc_buf->motion;
-			solo_enc->frames_since_last_motion = 0;
-			v4l2_event_queue(solo_enc->vfd, &ev);
-		}
-	}
-
-	vb2_buffer_done(vb, ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
-
-	return ret;
-}
-
-static void solo_enc_handle_one(struct solo_enc_dev *solo_enc,
-				struct solo_enc_buf *enc_buf)
-{
-	struct solo_vb2_buf *vb;
-	unsigned long flags;
-
-	mutex_lock(&solo_enc->lock);
-	if (solo_enc->type != enc_buf->type)
-		goto unlock;
-
-	spin_lock_irqsave(&solo_enc->av_lock, flags);
-	if (list_empty(&solo_enc->vidq_active)) {
-		spin_unlock_irqrestore(&solo_enc->av_lock, flags);
-		goto unlock;
-	}
-	vb = list_first_entry(&solo_enc->vidq_active, struct solo_vb2_buf,
-		list);
-	list_del(&vb->list);
-	spin_unlock_irqrestore(&solo_enc->av_lock, flags);
-
-	solo_enc_fillbuf(solo_enc, &vb->vb, enc_buf);
-unlock:
-	mutex_unlock(&solo_enc->lock);
-}
-
-void solo_enc_v4l2_isr(struct solo_dev *solo_dev)
-{
-	wake_up_interruptible_all(&solo_dev->ring_thread_wait);
-}
-
-static void solo_handle_ring(struct solo_dev *solo_dev)
-{
-	for (;;) {
-		struct solo_enc_dev *solo_enc;
-		struct solo_enc_buf enc_buf;
-		u32 mpeg_current, off;
-		u8 ch;
-		u8 cur_q;
-
-		/* Check if the hardware has any new ones in the queue */
-		cur_q = solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xff;
-		if (cur_q == solo_dev->enc_idx)
-			break;
-
-		mpeg_current = solo_reg_read(solo_dev,
-					SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
-		solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS;
-
-		ch = (mpeg_current >> 24) & 0x1f;
-		off = mpeg_current & 0x00ffffff;
-
-		if (ch >= SOLO_MAX_CHANNELS) {
-			ch -= SOLO_MAX_CHANNELS;
-			enc_buf.type = SOLO_ENC_TYPE_EXT;
-		} else
-			enc_buf.type = SOLO_ENC_TYPE_STD;
-
-		solo_enc = solo_dev->v4l2_enc[ch];
-		if (solo_enc == NULL) {
-			dev_err(&solo_dev->pdev->dev,
-				"Got spurious packet for channel %d\n", ch);
-			continue;
-		}
-
-		/* FAIL... */
-		if (enc_get_mpeg_dma(solo_dev, solo_dev->vh_dma, off,
-				     sizeof(vop_header)))
-			continue;
-
-		enc_buf.vh = solo_dev->vh_buf;
-
-		/* Sanity check */
-		if (vop_mpeg_offset(enc_buf.vh) !=
-			SOLO_MP4E_EXT_ADDR(solo_dev) + off)
-			continue;
-
-		if (solo_motion_detected(solo_enc))
-			enc_buf.motion = 1;
-		else
-			enc_buf.motion = 0;
-
-		solo_enc_handle_one(solo_enc, &enc_buf);
-	}
-}
-
-static int solo_ring_thread(void *data)
-{
-	struct solo_dev *solo_dev = data;
-	DECLARE_WAITQUEUE(wait, current);
-
-	set_freezable();
-	add_wait_queue(&solo_dev->ring_thread_wait, &wait);
-
-	for (;;) {
-		long timeout = schedule_timeout_interruptible(HZ);
-
-		if (timeout == -ERESTARTSYS || kthread_should_stop())
-			break;
-		solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
-		solo_handle_ring(solo_dev);
-		solo_irq_on(solo_dev, SOLO_IRQ_ENCODER);
-		try_to_freeze();
-	}
-
-	remove_wait_queue(&solo_dev->ring_thread_wait, &wait);
-
-	return 0;
-}
-
-static int solo_enc_queue_setup(struct vb2_queue *q,
-				const struct v4l2_format *fmt,
-				unsigned int *num_buffers,
-				unsigned int *num_planes, unsigned int sizes[],
-				void *alloc_ctxs[])
-{
-	sizes[0] = FRAME_BUF_SIZE;
-	*num_planes = 1;
-
-	if (*num_buffers < MIN_VID_BUFFERS)
-		*num_buffers = MIN_VID_BUFFERS;
-
-	return 0;
-}
-
-static void solo_enc_buf_queue(struct vb2_buffer *vb)
-{
-	struct vb2_queue *vq = vb->vb2_queue;
-	struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vq);
-	struct solo_vb2_buf *solo_vb =
-		container_of(vb, struct solo_vb2_buf, vb);
-
-	spin_lock(&solo_enc->av_lock);
-	list_add_tail(&solo_vb->list, &solo_enc->vidq_active);
-	spin_unlock(&solo_enc->av_lock);
-}
-
-static int solo_ring_start(struct solo_dev *solo_dev)
-{
-	solo_dev->ring_thread = kthread_run(solo_ring_thread, solo_dev,
-					    SOLO6X10_NAME "_ring");
-	if (IS_ERR(solo_dev->ring_thread)) {
-		int err = PTR_ERR(solo_dev->ring_thread);
-
-		solo_dev->ring_thread = NULL;
-		return err;
-	}
-
-	solo_irq_on(solo_dev, SOLO_IRQ_ENCODER);
-
-	return 0;
-}
-
-static void solo_ring_stop(struct solo_dev *solo_dev)
-{
-	if (solo_dev->ring_thread) {
-		kthread_stop(solo_dev->ring_thread);
-		solo_dev->ring_thread = NULL;
-	}
-
-	solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
-}
-
-static int solo_enc_start_streaming(struct vb2_queue *q, unsigned int count)
-{
-	struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
-	int ret;
-
-	ret = solo_enc_on(solo_enc);
-	if (ret)
-		return ret;
-	return solo_ring_start(solo_enc->solo_dev);
-}
-
-static void solo_enc_stop_streaming(struct vb2_queue *q)
-{
-	struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
-
-	solo_enc_off(solo_enc);
-	INIT_LIST_HEAD(&solo_enc->vidq_active);
-	solo_ring_stop(solo_enc->solo_dev);
-}
-
-static struct vb2_ops solo_enc_video_qops = {
-	.queue_setup	= solo_enc_queue_setup,
-	.buf_queue	= solo_enc_buf_queue,
-	.start_streaming = solo_enc_start_streaming,
-	.stop_streaming = solo_enc_stop_streaming,
-	.wait_prepare	= vb2_ops_wait_prepare,
-	.wait_finish	= vb2_ops_wait_finish,
-};
-
-static int solo_enc_querycap(struct file *file, void  *priv,
-			     struct v4l2_capability *cap)
-{
-	struct solo_enc_dev *solo_enc = video_drvdata(file);
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-	strcpy(cap->driver, SOLO6X10_NAME);
-	snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d",
-		 solo_enc->ch);
-	snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
-		 pci_name(solo_dev->pdev));
-	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
-			V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
-	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-	return 0;
-}
-
-static int solo_enc_enum_input(struct file *file, void *priv,
-			       struct v4l2_input *input)
-{
-	struct solo_enc_dev *solo_enc = video_drvdata(file);
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-	if (input->index)
-		return -EINVAL;
-
-	snprintf(input->name, sizeof(input->name), "Encoder %d",
-		 solo_enc->ch + 1);
-	input->type = V4L2_INPUT_TYPE_CAMERA;
-	input->std = solo_enc->vfd->tvnorms;
-
-	if (!tw28_get_video_status(solo_dev, solo_enc->ch))
-		input->status = V4L2_IN_ST_NO_SIGNAL;
-
-	return 0;
-}
-
-static int solo_enc_set_input(struct file *file, void *priv,
-			      unsigned int index)
-{
-	if (index)
-		return -EINVAL;
-
-	return 0;
-}
-
-static int solo_enc_get_input(struct file *file, void *priv,
-			      unsigned int *index)
-{
-	*index = 0;
-
-	return 0;
-}
-
-static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
-				 struct v4l2_fmtdesc *f)
-{
-	struct solo_enc_dev *solo_enc = video_drvdata(file);
-	int dev_type = solo_enc->solo_dev->type;
-
-	switch (f->index) {
-	case 0:
-		switch (dev_type) {
-		case SOLO_DEV_6010:
-			f->pixelformat = V4L2_PIX_FMT_MPEG4;
-			strcpy(f->description, "MPEG-4 part 2");
-			break;
-		case SOLO_DEV_6110:
-			f->pixelformat = V4L2_PIX_FMT_H264;
-			strcpy(f->description, "H.264");
-			break;
-		}
-		break;
-	case 1:
-		f->pixelformat = V4L2_PIX_FMT_MJPEG;
-		strcpy(f->description, "MJPEG");
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	f->flags = V4L2_FMT_FLAG_COMPRESSED;
-
-	return 0;
-}
-
-static inline int solo_valid_pixfmt(u32 pixfmt, int dev_type)
-{
-	return (pixfmt == V4L2_PIX_FMT_H264 && dev_type == SOLO_DEV_6110)
-		|| (pixfmt == V4L2_PIX_FMT_MPEG4 && dev_type == SOLO_DEV_6010)
-		|| pixfmt == V4L2_PIX_FMT_MJPEG ? 0 : -EINVAL;
-}
-
-static int solo_enc_try_fmt_cap(struct file *file, void *priv,
-			    struct v4l2_format *f)
-{
-	struct solo_enc_dev *solo_enc = video_drvdata(file);
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-	struct v4l2_pix_format *pix = &f->fmt.pix;
-
-	if (solo_valid_pixfmt(pix->pixelformat, solo_dev->type))
-		return -EINVAL;
-
-	if (pix->width < solo_dev->video_hsize ||
-	    pix->height < solo_dev->video_vsize << 1) {
-		/* Default to CIF 1/2 size */
-		pix->width = solo_dev->video_hsize >> 1;
-		pix->height = solo_dev->video_vsize;
-	} else {
-		/* Full frame */
-		pix->width = solo_dev->video_hsize;
-		pix->height = solo_dev->video_vsize << 1;
-	}
-
-	switch (pix->field) {
-	case V4L2_FIELD_NONE:
-	case V4L2_FIELD_INTERLACED:
-		break;
-	case V4L2_FIELD_ANY:
-	default:
-		pix->field = V4L2_FIELD_INTERLACED;
-		break;
-	}
-
-	/* Just set these */
-	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
-	pix->sizeimage = FRAME_BUF_SIZE;
-	pix->bytesperline = 0;
-	pix->priv = 0;
-
-	return 0;
-}
-
-static int solo_enc_set_fmt_cap(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct solo_enc_dev *solo_enc = video_drvdata(file);
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-	struct v4l2_pix_format *pix = &f->fmt.pix;
-	int ret;
-
-	if (vb2_is_busy(&solo_enc->vidq))
-		return -EBUSY;
-
-	ret = solo_enc_try_fmt_cap(file, priv, f);
-	if (ret)
-		return ret;
-
-	if (pix->width == solo_dev->video_hsize)
-		solo_enc->mode = SOLO_ENC_MODE_D1;
-	else
-		solo_enc->mode = SOLO_ENC_MODE_CIF;
-
-	/* This does not change the encoder at all */
-	solo_enc->fmt = pix->pixelformat;
-
-	/*
-	 * More information is needed about these 'extended' types. As far
-	 * as I can tell these are basically additional video streams with
-	 * different MPEG encoding attributes that can run in parallel with
-	 * the main stream. If so, then this should be implemented as a
-	 * second video node. Abusing priv like this is certainly not the
-	 * right approach.
-	if (pix->priv)
-		solo_enc->type = SOLO_ENC_TYPE_EXT;
-	 */
-	solo_update_mode(solo_enc);
-	return 0;
-}
-
-static int solo_enc_get_fmt_cap(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct solo_enc_dev *solo_enc = video_drvdata(file);
-	struct v4l2_pix_format *pix = &f->fmt.pix;
-
-	pix->width = solo_enc->width;
-	pix->height = solo_enc->height;
-	pix->pixelformat = solo_enc->fmt;
-	pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
-		     V4L2_FIELD_NONE;
-	pix->sizeimage = FRAME_BUF_SIZE;
-	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
-	pix->priv = 0;
-
-	return 0;
-}
-
-static int solo_enc_g_std(struct file *file, void *priv, v4l2_std_id *i)
-{
-	struct solo_enc_dev *solo_enc = video_drvdata(file);
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-	if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
-		*i = V4L2_STD_NTSC_M;
-	else
-		*i = V4L2_STD_PAL;
-	return 0;
-}
-
-static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id std)
-{
-	struct solo_enc_dev *solo_enc = video_drvdata(file);
-
-	return solo_set_video_type(solo_enc->solo_dev, std & V4L2_STD_625_50);
-}
-
-static int solo_enum_framesizes(struct file *file, void *priv,
-				struct v4l2_frmsizeenum *fsize)
-{
-	struct solo_enc_dev *solo_enc = video_drvdata(file);
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-	if (solo_valid_pixfmt(fsize->pixel_format, solo_dev->type))
-		return -EINVAL;
-
-	switch (fsize->index) {
-	case 0:
-		fsize->discrete.width = solo_dev->video_hsize >> 1;
-		fsize->discrete.height = solo_dev->video_vsize;
-		break;
-	case 1:
-		fsize->discrete.width = solo_dev->video_hsize;
-		fsize->discrete.height = solo_dev->video_vsize << 1;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
-
-	return 0;
-}
-
-static int solo_enum_frameintervals(struct file *file, void *priv,
-				    struct v4l2_frmivalenum *fintv)
-{
-	struct solo_enc_dev *solo_enc = video_drvdata(file);
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-	if (solo_valid_pixfmt(fintv->pixel_format, solo_dev->type))
-		return -EINVAL;
-	if (fintv->index)
-		return -EINVAL;
-	if ((fintv->width != solo_dev->video_hsize >> 1 ||
-	     fintv->height != solo_dev->video_vsize) &&
-	    (fintv->width != solo_dev->video_hsize ||
-	     fintv->height != solo_dev->video_vsize << 1))
-		return -EINVAL;
-
-	fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
-
-	fintv->stepwise.min.numerator = 1;
-	fintv->stepwise.min.denominator = solo_dev->fps;
-
-	fintv->stepwise.max.numerator = 15;
-	fintv->stepwise.max.denominator = solo_dev->fps;
-
-	fintv->stepwise.step.numerator = 1;
-	fintv->stepwise.step.denominator = solo_dev->fps;
-
-	return 0;
-}
-
-static int solo_g_parm(struct file *file, void *priv,
-		       struct v4l2_streamparm *sp)
-{
-	struct solo_enc_dev *solo_enc = video_drvdata(file);
-	struct v4l2_captureparm *cp = &sp->parm.capture;
-
-	cp->capability = V4L2_CAP_TIMEPERFRAME;
-	cp->timeperframe.numerator = solo_enc->interval;
-	cp->timeperframe.denominator = solo_enc->solo_dev->fps;
-	cp->capturemode = 0;
-	/* XXX: Shouldn't we be able to get/set this from videobuf? */
-	cp->readbuffers = 2;
-
-	return 0;
-}
-
-static inline int calc_interval(u8 fps, u32 n, u32 d)
-{
-	if (!n || !d)
-		return 1;
-	if (d == fps)
-		return n;
-	n *= fps;
-	return min(15U, n / d + (n % d >= (fps >> 1)));
-}
-
-static int solo_s_parm(struct file *file, void *priv,
-		       struct v4l2_streamparm *sp)
-{
-	struct solo_enc_dev *solo_enc = video_drvdata(file);
-	struct v4l2_fract *t = &sp->parm.capture.timeperframe;
-	u8 fps = solo_enc->solo_dev->fps;
-
-	if (vb2_is_streaming(&solo_enc->vidq))
-		return -EBUSY;
-
-	solo_enc->interval = calc_interval(fps, t->numerator, t->denominator);
-	solo_update_mode(solo_enc);
-	return solo_g_parm(file, priv, sp);
-}
-
-static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-	struct solo_enc_dev *solo_enc =
-		container_of(ctrl->handler, struct solo_enc_dev, hdl);
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-	int err;
-
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-	case V4L2_CID_CONTRAST:
-	case V4L2_CID_SATURATION:
-	case V4L2_CID_HUE:
-	case V4L2_CID_SHARPNESS:
-		return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
-					 ctrl->val);
-	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
-		solo_enc->gop = ctrl->val;
-		solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch), solo_enc->gop);
-		solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch), solo_enc->gop);
-		return 0;
-	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
-		solo_enc->qp = ctrl->val;
-		solo_reg_write(solo_dev, SOLO_VE_CH_QP(solo_enc->ch), solo_enc->qp);
-		solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(solo_enc->ch), solo_enc->qp);
-		return 0;
-	case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD:
-		solo_enc->motion_thresh = ctrl->val << 8;
-		if (!solo_enc->motion_global || !solo_enc->motion_enabled)
-			return 0;
-		return solo_set_motion_threshold(solo_dev, solo_enc->ch,
-				solo_enc->motion_thresh);
-	case V4L2_CID_DETECT_MD_MODE:
-		solo_enc->motion_global = ctrl->val == V4L2_DETECT_MD_MODE_GLOBAL;
-		solo_enc->motion_enabled = ctrl->val > V4L2_DETECT_MD_MODE_DISABLED;
-		if (ctrl->val) {
-			if (solo_enc->motion_global)
-				solo_set_motion_threshold(solo_dev, solo_enc->ch,
-					solo_enc->motion_thresh);
-			else
-				solo_set_motion_block(solo_dev, solo_enc->ch,
-					solo_enc->md_thresholds->p_cur.p_u16);
-		}
-		solo_motion_toggle(solo_enc, ctrl->val);
-		return 0;
-	case V4L2_CID_DETECT_MD_THRESHOLD_GRID:
-		if (solo_enc->motion_enabled && !solo_enc->motion_global)
-			return solo_set_motion_block(solo_dev, solo_enc->ch,
-					solo_enc->md_thresholds->p_new.p_u16);
-		break;
-	case V4L2_CID_OSD_TEXT:
-		strcpy(solo_enc->osd_text, ctrl->p_new.p_char);
-		err = solo_osd_print(solo_enc);
-		return err;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int solo_subscribe_event(struct v4l2_fh *fh,
-				const struct v4l2_event_subscription *sub)
-{
-
-	switch (sub->type) {
-	case V4L2_EVENT_CTRL:
-		return v4l2_ctrl_subscribe_event(fh, sub);
-	case V4L2_EVENT_MOTION_DET:
-		/* Allow for up to 30 events (1 second for NTSC) to be
-		 * stored. */
-		return v4l2_event_subscribe(fh, sub, 30, NULL);
-	}
-	return -EINVAL;
-}
-
-static const struct v4l2_file_operations solo_enc_fops = {
-	.owner			= THIS_MODULE,
-	.open			= v4l2_fh_open,
-	.release		= vb2_fop_release,
-	.read			= vb2_fop_read,
-	.poll			= vb2_fop_poll,
-	.mmap			= vb2_fop_mmap,
-	.unlocked_ioctl		= video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
-	.vidioc_querycap		= solo_enc_querycap,
-	.vidioc_s_std			= solo_enc_s_std,
-	.vidioc_g_std			= solo_enc_g_std,
-	/* Input callbacks */
-	.vidioc_enum_input		= solo_enc_enum_input,
-	.vidioc_s_input			= solo_enc_set_input,
-	.vidioc_g_input			= solo_enc_get_input,
-	/* Video capture format callbacks */
-	.vidioc_enum_fmt_vid_cap	= solo_enc_enum_fmt_cap,
-	.vidioc_try_fmt_vid_cap		= solo_enc_try_fmt_cap,
-	.vidioc_s_fmt_vid_cap		= solo_enc_set_fmt_cap,
-	.vidioc_g_fmt_vid_cap		= solo_enc_get_fmt_cap,
-	/* Streaming I/O */
-	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
-	.vidioc_querybuf		= vb2_ioctl_querybuf,
-	.vidioc_qbuf			= vb2_ioctl_qbuf,
-	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
-	.vidioc_streamon		= vb2_ioctl_streamon,
-	.vidioc_streamoff		= vb2_ioctl_streamoff,
-	/* Frame size and interval */
-	.vidioc_enum_framesizes		= solo_enum_framesizes,
-	.vidioc_enum_frameintervals	= solo_enum_frameintervals,
-	/* Video capture parameters */
-	.vidioc_s_parm			= solo_s_parm,
-	.vidioc_g_parm			= solo_g_parm,
-	/* Logging and events */
-	.vidioc_log_status		= v4l2_ctrl_log_status,
-	.vidioc_subscribe_event		= solo_subscribe_event,
-	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
-};
-
-static const struct video_device solo_enc_template = {
-	.name			= SOLO6X10_NAME,
-	.fops			= &solo_enc_fops,
-	.ioctl_ops		= &solo_enc_ioctl_ops,
-	.minor			= -1,
-	.release		= video_device_release,
-	.tvnorms		= V4L2_STD_NTSC_M | V4L2_STD_PAL,
-};
-
-static const struct v4l2_ctrl_ops solo_ctrl_ops = {
-	.s_ctrl = solo_s_ctrl,
-};
-
-static const struct v4l2_ctrl_config solo_osd_text_ctrl = {
-	.ops = &solo_ctrl_ops,
-	.id = V4L2_CID_OSD_TEXT,
-	.name = "OSD Text",
-	.type = V4L2_CTRL_TYPE_STRING,
-	.max = OSD_TEXT_MAX,
-	.step = 1,
-};
-
-/* Motion Detection Threshold matrix */
-static const struct v4l2_ctrl_config solo_md_thresholds = {
-	.ops = &solo_ctrl_ops,
-	.id = V4L2_CID_DETECT_MD_THRESHOLD_GRID,
-	.dims = { SOLO_MOTION_SZ, SOLO_MOTION_SZ },
-	.def = SOLO_DEF_MOT_THRESH,
-	.max = 65535,
-	.step = 1,
-};
-
-static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
-					   u8 ch, unsigned nr)
-{
-	struct solo_enc_dev *solo_enc;
-	struct v4l2_ctrl_handler *hdl;
-	int ret;
-
-	solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
-	if (!solo_enc)
-		return ERR_PTR(-ENOMEM);
-
-	hdl = &solo_enc->hdl;
-	v4l2_ctrl_handler_init(hdl, 10);
-	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
-			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
-	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
-			V4L2_CID_CONTRAST, 0, 255, 1, 128);
-	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
-			V4L2_CID_SATURATION, 0, 255, 1, 128);
-	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
-			V4L2_CID_HUE, 0, 255, 1, 128);
-	if (tw28_has_sharpness(solo_dev, ch))
-		v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
-			V4L2_CID_SHARPNESS, 0, 15, 1, 0);
-	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
-			V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, solo_dev->fps);
-	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
-			V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 31, 1, SOLO_DEFAULT_QP);
-	v4l2_ctrl_new_std_menu(hdl, &solo_ctrl_ops,
-			V4L2_CID_DETECT_MD_MODE,
-			V4L2_DETECT_MD_MODE_THRESHOLD_GRID, 0,
-			V4L2_DETECT_MD_MODE_DISABLED);
-	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
-			V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD, 0, 0xff, 1,
-			SOLO_DEF_MOT_THRESH >> 8);
-	v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL);
-	solo_enc->md_thresholds =
-		v4l2_ctrl_new_custom(hdl, &solo_md_thresholds, NULL);
-	if (hdl->error) {
-		ret = hdl->error;
-		goto hdl_free;
-	}
-
-	solo_enc->solo_dev = solo_dev;
-	solo_enc->ch = ch;
-	mutex_init(&solo_enc->lock);
-	spin_lock_init(&solo_enc->av_lock);
-	INIT_LIST_HEAD(&solo_enc->vidq_active);
-	solo_enc->fmt = (solo_dev->type == SOLO_DEV_6010) ?
-		V4L2_PIX_FMT_MPEG4 : V4L2_PIX_FMT_H264;
-	solo_enc->type = SOLO_ENC_TYPE_STD;
-
-	solo_enc->qp = SOLO_DEFAULT_QP;
-	solo_enc->gop = solo_dev->fps;
-	solo_enc->interval = 1;
-	solo_enc->mode = SOLO_ENC_MODE_CIF;
-	solo_enc->motion_global = true;
-	solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
-	solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
-	solo_enc->vidq.ops = &solo_enc_video_qops;
-	solo_enc->vidq.mem_ops = &vb2_dma_sg_memops;
-	solo_enc->vidq.drv_priv = solo_enc;
-	solo_enc->vidq.gfp_flags = __GFP_DMA32;
-	solo_enc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
-	solo_enc->vidq.buf_struct_size = sizeof(struct solo_vb2_buf);
-	solo_enc->vidq.lock = &solo_enc->lock;
-	ret = vb2_queue_init(&solo_enc->vidq);
-	if (ret)
-		goto hdl_free;
-	solo_update_mode(solo_enc);
-
-	spin_lock_init(&solo_enc->motion_lock);
-
-	/* Initialize this per encoder */
-	solo_enc->jpeg_len = sizeof(jpeg_header);
-	memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len);
-
-	solo_enc->desc_nelts = 32;
-	solo_enc->desc_items = pci_alloc_consistent(solo_dev->pdev,
-				      sizeof(struct solo_p2m_desc) *
-				      solo_enc->desc_nelts,
-				      &solo_enc->desc_dma);
-	ret = -ENOMEM;
-	if (solo_enc->desc_items == NULL)
-		goto hdl_free;
-
-	solo_enc->vfd = video_device_alloc();
-	if (!solo_enc->vfd)
-		goto pci_free;
-
-	*solo_enc->vfd = solo_enc_template;
-	solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev;
-	solo_enc->vfd->ctrl_handler = hdl;
-	solo_enc->vfd->queue = &solo_enc->vidq;
-	solo_enc->vfd->lock = &solo_enc->lock;
-	video_set_drvdata(solo_enc->vfd, solo_enc);
-	ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr);
-	if (ret < 0)
-		goto vdev_release;
-
-	snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
-		 "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num,
-		 solo_enc->vfd->num);
-
-	return solo_enc;
-
-vdev_release:
-	video_device_release(solo_enc->vfd);
-pci_free:
-	pci_free_consistent(solo_enc->solo_dev->pdev,
-			sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts,
-			solo_enc->desc_items, solo_enc->desc_dma);
-hdl_free:
-	v4l2_ctrl_handler_free(hdl);
-	kfree(solo_enc);
-	return ERR_PTR(ret);
-}
-
-static void solo_enc_free(struct solo_enc_dev *solo_enc)
-{
-	if (solo_enc == NULL)
-		return;
-
-	video_unregister_device(solo_enc->vfd);
-	v4l2_ctrl_handler_free(&solo_enc->hdl);
-	kfree(solo_enc);
-}
-
-int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
-{
-	int i;
-
-	init_waitqueue_head(&solo_dev->ring_thread_wait);
-
-	solo_dev->vh_size = sizeof(vop_header);
-	solo_dev->vh_buf = pci_alloc_consistent(solo_dev->pdev,
-						solo_dev->vh_size,
-						&solo_dev->vh_dma);
-	if (solo_dev->vh_buf == NULL)
-		return -ENOMEM;
-
-	for (i = 0; i < solo_dev->nr_chans; i++) {
-		solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i, nr);
-		if (IS_ERR(solo_dev->v4l2_enc[i]))
-			break;
-	}
-
-	if (i != solo_dev->nr_chans) {
-		int ret = PTR_ERR(solo_dev->v4l2_enc[i]);
-
-		while (i--)
-			solo_enc_free(solo_dev->v4l2_enc[i]);
-		pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
-				    solo_dev->vh_buf, solo_dev->vh_dma);
-		solo_dev->vh_buf = NULL;
-		return ret;
-	}
-
-	if (solo_dev->type == SOLO_DEV_6010)
-		solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4;
-	else
-		solo_dev->enc_bw_remain = solo_dev->fps * 4 * 5;
-
-	dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n",
-		 solo_dev->v4l2_enc[0]->vfd->num,
-		 solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num);
-
-	return 0;
-}
-
-void solo_enc_v4l2_exit(struct solo_dev *solo_dev)
-{
-	int i;
-
-	for (i = 0; i < solo_dev->nr_chans; i++)
-		solo_enc_free(solo_dev->v4l2_enc[i]);
-
-	if (solo_dev->vh_buf)
-		pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
-			    solo_dev->vh_buf, solo_dev->vh_dma);
-}
diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2.c b/drivers/staging/media/solo6x10/solo6x10-v4l2.c
deleted file mode 100644
index 63ae8a61f6030..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2.c
+++ /dev/null
@@ -1,733 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-event.h>
-#include <media/videobuf2-dma-contig.h>
-
-#include "solo6x10.h"
-#include "solo6x10-tw28.h"
-
-/* Image size is two fields, SOLO_HW_BPL is one horizontal line in hardware */
-#define SOLO_HW_BPL		2048
-#define solo_vlines(__solo)	(__solo->video_vsize * 2)
-#define solo_image_size(__solo) (solo_bytesperline(__solo) * \
-				 solo_vlines(__solo))
-#define solo_bytesperline(__solo) (__solo->video_hsize * 2)
-
-#define MIN_VID_BUFFERS		2
-
-static inline void erase_on(struct solo_dev *solo_dev)
-{
-	solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
-	solo_dev->erasing = 1;
-	solo_dev->frame_blank = 0;
-}
-
-static inline int erase_off(struct solo_dev *solo_dev)
-{
-	if (!solo_dev->erasing)
-		return 0;
-
-	/* First time around, assert erase off */
-	if (!solo_dev->frame_blank)
-		solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0);
-	/* Keep the erasing flag on for 8 frames minimum */
-	if (solo_dev->frame_blank++ >= 8)
-		solo_dev->erasing = 0;
-
-	return 1;
-}
-
-void solo_video_in_isr(struct solo_dev *solo_dev)
-{
-	wake_up_interruptible_all(&solo_dev->disp_thread_wait);
-}
-
-static void solo_win_setup(struct solo_dev *solo_dev, u8 ch,
-			   int sx, int sy, int ex, int ey, int scale)
-{
-	if (ch >= solo_dev->nr_chans)
-		return;
-
-	/* Here, we just keep window/channel the same */
-	solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch),
-		       SOLO_VI_WIN_CHANNEL(ch) |
-		       SOLO_VI_WIN_SX(sx) |
-		       SOLO_VI_WIN_EX(ex) |
-		       SOLO_VI_WIN_SCALE(scale));
-
-	solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
-		       SOLO_VI_WIN_SY(sy) |
-		       SOLO_VI_WIN_EY(ey));
-}
-
-static int solo_v4l2_ch_ext_4up(struct solo_dev *solo_dev, u8 idx, int on)
-{
-	u8 ch = idx * 4;
-
-	if (ch >= solo_dev->nr_chans)
-		return -EINVAL;
-
-	if (!on) {
-		u8 i;
-
-		for (i = ch; i < ch + 4; i++)
-			solo_win_setup(solo_dev, i, solo_dev->video_hsize,
-				       solo_vlines(solo_dev),
-				       solo_dev->video_hsize,
-				       solo_vlines(solo_dev), 0);
-		return 0;
-	}
-
-	/* Row 1 */
-	solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2,
-		       solo_vlines(solo_dev) / 2, 3);
-	solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0,
-		       solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3);
-	/* Row 2 */
-	solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2,
-		       solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3);
-	solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2,
-		       solo_vlines(solo_dev) / 2, solo_dev->video_hsize,
-		       solo_vlines(solo_dev), 3);
-
-	return 0;
-}
-
-static int solo_v4l2_ch_ext_16up(struct solo_dev *solo_dev, int on)
-{
-	int sy, ysize, hsize, i;
-
-	if (!on) {
-		for (i = 0; i < 16; i++)
-			solo_win_setup(solo_dev, i, solo_dev->video_hsize,
-				       solo_vlines(solo_dev),
-				       solo_dev->video_hsize,
-				       solo_vlines(solo_dev), 0);
-		return 0;
-	}
-
-	ysize = solo_vlines(solo_dev) / 4;
-	hsize = solo_dev->video_hsize / 4;
-
-	for (sy = 0, i = 0; i < 4; i++, sy += ysize) {
-		solo_win_setup(solo_dev, i * 4, 0, sy, hsize,
-			       sy + ysize, 5);
-		solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy,
-			       hsize * 2, sy + ysize, 5);
-		solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy,
-			       hsize * 3, sy + ysize, 5);
-		solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy,
-			       solo_dev->video_hsize, sy + ysize, 5);
-	}
-
-	return 0;
-}
-
-static int solo_v4l2_ch(struct solo_dev *solo_dev, u8 ch, int on)
-{
-	u8 ext_ch;
-
-	if (ch < solo_dev->nr_chans) {
-		solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize,
-			       on ? 0 : solo_vlines(solo_dev),
-			       solo_dev->video_hsize, solo_vlines(solo_dev),
-			       on ? 1 : 0);
-		return 0;
-	}
-
-	if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
-		return -EINVAL;
-
-	ext_ch = ch - solo_dev->nr_chans;
-
-	/* 4up's first */
-	if (ext_ch < 4)
-		return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on);
-
-	/* Remaining case is 16up for 16-port */
-	return solo_v4l2_ch_ext_16up(solo_dev, on);
-}
-
-static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch)
-{
-	if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
-		return -EINVAL;
-
-	erase_on(solo_dev);
-
-	solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0);
-	solo_v4l2_ch(solo_dev, ch, 1);
-
-	solo_dev->cur_disp_ch = ch;
-
-	return 0;
-}
-
-static void solo_fillbuf(struct solo_dev *solo_dev,
-			 struct vb2_buffer *vb)
-{
-	dma_addr_t vbuf;
-	unsigned int fdma_addr;
-	int error = -1;
-	int i;
-
-	vbuf = vb2_dma_contig_plane_dma_addr(vb, 0);
-	if (!vbuf)
-		goto finish_buf;
-
-	if (erase_off(solo_dev)) {
-		void *p = vb2_plane_vaddr(vb, 0);
-		int image_size = solo_image_size(solo_dev);
-
-		for (i = 0; i < image_size; i += 2) {
-			((u8 *)p)[i] = 0x80;
-			((u8 *)p)[i + 1] = 0x00;
-		}
-		error = 0;
-	} else {
-		fdma_addr = SOLO_DISP_EXT_ADDR + (solo_dev->old_write *
-				(SOLO_HW_BPL * solo_vlines(solo_dev)));
-
-		error = solo_p2m_dma_t(solo_dev, 0, vbuf, fdma_addr,
-				       solo_bytesperline(solo_dev),
-				       solo_vlines(solo_dev), SOLO_HW_BPL);
-	}
-
-finish_buf:
-	if (!error) {
-		vb2_set_plane_payload(vb, 0,
-			solo_vlines(solo_dev) * solo_bytesperline(solo_dev));
-		vb->v4l2_buf.sequence = solo_dev->sequence++;
-		v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
-	}
-
-	vb2_buffer_done(vb, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
-}
-
-static void solo_thread_try(struct solo_dev *solo_dev)
-{
-	struct solo_vb2_buf *vb;
-
-	/* Only "break" from this loop if slock is held, otherwise
-	 * just return. */
-	for (;;) {
-		unsigned int cur_write;
-
-		cur_write = SOLO_VI_STATUS0_PAGE(
-			solo_reg_read(solo_dev, SOLO_VI_STATUS0));
-		if (cur_write == solo_dev->old_write)
-			return;
-
-		spin_lock(&solo_dev->slock);
-
-		if (list_empty(&solo_dev->vidq_active))
-			break;
-
-		vb = list_first_entry(&solo_dev->vidq_active, struct solo_vb2_buf,
-				      list);
-
-		solo_dev->old_write = cur_write;
-		list_del(&vb->list);
-
-		spin_unlock(&solo_dev->slock);
-
-		solo_fillbuf(solo_dev, &vb->vb);
-	}
-
-	assert_spin_locked(&solo_dev->slock);
-	spin_unlock(&solo_dev->slock);
-}
-
-static int solo_thread(void *data)
-{
-	struct solo_dev *solo_dev = data;
-	DECLARE_WAITQUEUE(wait, current);
-
-	set_freezable();
-	add_wait_queue(&solo_dev->disp_thread_wait, &wait);
-
-	for (;;) {
-		long timeout = schedule_timeout_interruptible(HZ);
-
-		if (timeout == -ERESTARTSYS || kthread_should_stop())
-			break;
-		solo_thread_try(solo_dev);
-		try_to_freeze();
-	}
-
-	remove_wait_queue(&solo_dev->disp_thread_wait, &wait);
-
-	return 0;
-}
-
-static int solo_start_thread(struct solo_dev *solo_dev)
-{
-	int ret = 0;
-
-	solo_dev->kthread = kthread_run(solo_thread, solo_dev, SOLO6X10_NAME "_disp");
-
-	if (IS_ERR(solo_dev->kthread)) {
-		ret = PTR_ERR(solo_dev->kthread);
-		solo_dev->kthread = NULL;
-		return ret;
-	}
-	solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
-
-	return ret;
-}
-
-static void solo_stop_thread(struct solo_dev *solo_dev)
-{
-	if (!solo_dev->kthread)
-		return;
-
-	solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
-	kthread_stop(solo_dev->kthread);
-	solo_dev->kthread = NULL;
-}
-
-static int solo_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
-			   unsigned int *num_buffers, unsigned int *num_planes,
-			   unsigned int sizes[], void *alloc_ctxs[])
-{
-	struct solo_dev *solo_dev = vb2_get_drv_priv(q);
-
-	sizes[0] = solo_image_size(solo_dev);
-	alloc_ctxs[0] = solo_dev->alloc_ctx;
-	*num_planes = 1;
-
-	if (*num_buffers < MIN_VID_BUFFERS)
-		*num_buffers = MIN_VID_BUFFERS;
-
-	return 0;
-}
-
-static int solo_start_streaming(struct vb2_queue *q, unsigned int count)
-{
-	struct solo_dev *solo_dev = vb2_get_drv_priv(q);
-
-	solo_dev->sequence = 0;
-	return solo_start_thread(solo_dev);
-}
-
-static void solo_stop_streaming(struct vb2_queue *q)
-{
-	struct solo_dev *solo_dev = vb2_get_drv_priv(q);
-
-	solo_stop_thread(solo_dev);
-	INIT_LIST_HEAD(&solo_dev->vidq_active);
-}
-
-static void solo_buf_queue(struct vb2_buffer *vb)
-{
-	struct vb2_queue *vq = vb->vb2_queue;
-	struct solo_dev *solo_dev = vb2_get_drv_priv(vq);
-	struct solo_vb2_buf *solo_vb =
-		container_of(vb, struct solo_vb2_buf, vb);
-
-	spin_lock(&solo_dev->slock);
-	list_add_tail(&solo_vb->list, &solo_dev->vidq_active);
-	spin_unlock(&solo_dev->slock);
-	wake_up_interruptible(&solo_dev->disp_thread_wait);
-}
-
-static const struct vb2_ops solo_video_qops = {
-	.queue_setup	= solo_queue_setup,
-	.buf_queue	= solo_buf_queue,
-	.start_streaming = solo_start_streaming,
-	.stop_streaming = solo_stop_streaming,
-	.wait_prepare	= vb2_ops_wait_prepare,
-	.wait_finish	= vb2_ops_wait_finish,
-};
-
-static int solo_querycap(struct file *file, void  *priv,
-			 struct v4l2_capability *cap)
-{
-	struct solo_dev *solo_dev = video_drvdata(file);
-
-	strcpy(cap->driver, SOLO6X10_NAME);
-	strcpy(cap->card, "Softlogic 6x10");
-	snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
-		 pci_name(solo_dev->pdev));
-	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
-			V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
-	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-	return 0;
-}
-
-static int solo_enum_ext_input(struct solo_dev *solo_dev,
-			       struct v4l2_input *input)
-{
-	static const char * const dispnames_1[] = { "4UP" };
-	static const char * const dispnames_2[] = { "4UP-1", "4UP-2" };
-	static const char * const dispnames_5[] = {
-		"4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP"
-	};
-	const char * const *dispnames;
-
-	if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext))
-		return -EINVAL;
-
-	if (solo_dev->nr_ext == 5)
-		dispnames = dispnames_5;
-	else if (solo_dev->nr_ext == 2)
-		dispnames = dispnames_2;
-	else
-		dispnames = dispnames_1;
-
-	snprintf(input->name, sizeof(input->name), "Multi %s",
-		 dispnames[input->index - solo_dev->nr_chans]);
-
-	return 0;
-}
-
-static int solo_enum_input(struct file *file, void *priv,
-			   struct v4l2_input *input)
-{
-	struct solo_dev *solo_dev = video_drvdata(file);
-
-	if (input->index >= solo_dev->nr_chans) {
-		int ret = solo_enum_ext_input(solo_dev, input);
-
-		if (ret < 0)
-			return ret;
-	} else {
-		snprintf(input->name, sizeof(input->name), "Camera %d",
-			 input->index + 1);
-
-		/* We can only check this for normal inputs */
-		if (!tw28_get_video_status(solo_dev, input->index))
-			input->status = V4L2_IN_ST_NO_SIGNAL;
-	}
-
-	input->type = V4L2_INPUT_TYPE_CAMERA;
-	input->std = solo_dev->vfd->tvnorms;
-	return 0;
-}
-
-static int solo_set_input(struct file *file, void *priv, unsigned int index)
-{
-	struct solo_dev *solo_dev = video_drvdata(file);
-	int ret = solo_v4l2_set_ch(solo_dev, index);
-
-	if (!ret) {
-		while (erase_off(solo_dev))
-			/* Do nothing */;
-	}
-
-	return ret;
-}
-
-static int solo_get_input(struct file *file, void *priv, unsigned int *index)
-{
-	struct solo_dev *solo_dev = video_drvdata(file);
-
-	*index = solo_dev->cur_disp_ch;
-
-	return 0;
-}
-
-static int solo_enum_fmt_cap(struct file *file, void *priv,
-			     struct v4l2_fmtdesc *f)
-{
-	if (f->index)
-		return -EINVAL;
-
-	f->pixelformat = V4L2_PIX_FMT_UYVY;
-	strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));
-
-	return 0;
-}
-
-static int solo_try_fmt_cap(struct file *file, void *priv,
-			    struct v4l2_format *f)
-{
-	struct solo_dev *solo_dev = video_drvdata(file);
-	struct v4l2_pix_format *pix = &f->fmt.pix;
-	int image_size = solo_image_size(solo_dev);
-
-	if (pix->pixelformat != V4L2_PIX_FMT_UYVY)
-		return -EINVAL;
-
-	pix->width = solo_dev->video_hsize;
-	pix->height = solo_vlines(solo_dev);
-	pix->sizeimage = image_size;
-	pix->field = V4L2_FIELD_INTERLACED;
-	pix->pixelformat = V4L2_PIX_FMT_UYVY;
-	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
-	pix->priv = 0;
-	return 0;
-}
-
-static int solo_set_fmt_cap(struct file *file, void *priv,
-			    struct v4l2_format *f)
-{
-	struct solo_dev *solo_dev = video_drvdata(file);
-
-	if (vb2_is_busy(&solo_dev->vidq))
-		return -EBUSY;
-
-	/* For right now, if it doesn't match our running config,
-	 * then fail */
-	return solo_try_fmt_cap(file, priv, f);
-}
-
-static int solo_get_fmt_cap(struct file *file, void *priv,
-			    struct v4l2_format *f)
-{
-	struct solo_dev *solo_dev = video_drvdata(file);
-	struct v4l2_pix_format *pix = &f->fmt.pix;
-
-	pix->width = solo_dev->video_hsize;
-	pix->height = solo_vlines(solo_dev);
-	pix->pixelformat = V4L2_PIX_FMT_UYVY;
-	pix->field = V4L2_FIELD_INTERLACED;
-	pix->sizeimage = solo_image_size(solo_dev);
-	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
-	pix->bytesperline = solo_bytesperline(solo_dev);
-	pix->priv = 0;
-
-	return 0;
-}
-
-static int solo_g_std(struct file *file, void *priv, v4l2_std_id *i)
-{
-	struct solo_dev *solo_dev = video_drvdata(file);
-
-	if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
-		*i = V4L2_STD_NTSC_M;
-	else
-		*i = V4L2_STD_PAL;
-	return 0;
-}
-
-int solo_set_video_type(struct solo_dev *solo_dev, bool is_50hz)
-{
-	int i;
-
-	/* Make sure all video nodes are idle */
-	if (vb2_is_busy(&solo_dev->vidq))
-		return -EBUSY;
-	for (i = 0; i < solo_dev->nr_chans; i++)
-		if (vb2_is_busy(&solo_dev->v4l2_enc[i]->vidq))
-			return -EBUSY;
-	solo_dev->video_type = is_50hz ? SOLO_VO_FMT_TYPE_PAL :
-					 SOLO_VO_FMT_TYPE_NTSC;
-	/* Reconfigure for the new standard */
-	solo_disp_init(solo_dev);
-	solo_enc_init(solo_dev);
-	solo_tw28_init(solo_dev);
-	for (i = 0; i < solo_dev->nr_chans; i++)
-		solo_update_mode(solo_dev->v4l2_enc[i]);
-	return solo_v4l2_set_ch(solo_dev, solo_dev->cur_disp_ch);
-}
-
-static int solo_s_std(struct file *file, void *priv, v4l2_std_id std)
-{
-	struct solo_dev *solo_dev = video_drvdata(file);
-
-	return solo_set_video_type(solo_dev, std & V4L2_STD_625_50);
-}
-
-static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-	struct solo_dev *solo_dev =
-		container_of(ctrl->handler, struct solo_dev, disp_hdl);
-
-	switch (ctrl->id) {
-	case V4L2_CID_MOTION_TRACE:
-		if (ctrl->val) {
-			solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER,
-					SOLO_VI_MOTION_Y_ADD |
-					SOLO_VI_MOTION_Y_VALUE(0x20) |
-					SOLO_VI_MOTION_CB_VALUE(0x10) |
-					SOLO_VI_MOTION_CR_VALUE(0x10));
-			solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR,
-					SOLO_VI_MOTION_CR_ADD |
-					SOLO_VI_MOTION_Y_VALUE(0x10) |
-					SOLO_VI_MOTION_CB_VALUE(0x80) |
-					SOLO_VI_MOTION_CR_VALUE(0x10));
-		} else {
-			solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
-			solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
-		}
-		return 0;
-	default:
-		break;
-	}
-	return -EINVAL;
-}
-
-static const struct v4l2_file_operations solo_v4l2_fops = {
-	.owner			= THIS_MODULE,
-	.open			= v4l2_fh_open,
-	.release		= vb2_fop_release,
-	.read			= vb2_fop_read,
-	.poll			= vb2_fop_poll,
-	.mmap			= vb2_fop_mmap,
-	.unlocked_ioctl		= video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
-	.vidioc_querycap		= solo_querycap,
-	.vidioc_s_std			= solo_s_std,
-	.vidioc_g_std			= solo_g_std,
-	/* Input callbacks */
-	.vidioc_enum_input		= solo_enum_input,
-	.vidioc_s_input			= solo_set_input,
-	.vidioc_g_input			= solo_get_input,
-	/* Video capture format callbacks */
-	.vidioc_enum_fmt_vid_cap	= solo_enum_fmt_cap,
-	.vidioc_try_fmt_vid_cap		= solo_try_fmt_cap,
-	.vidioc_s_fmt_vid_cap		= solo_set_fmt_cap,
-	.vidioc_g_fmt_vid_cap		= solo_get_fmt_cap,
-	/* Streaming I/O */
-	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
-	.vidioc_querybuf		= vb2_ioctl_querybuf,
-	.vidioc_qbuf			= vb2_ioctl_qbuf,
-	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
-	.vidioc_streamon		= vb2_ioctl_streamon,
-	.vidioc_streamoff		= vb2_ioctl_streamoff,
-	/* Logging and events */
-	.vidioc_log_status		= v4l2_ctrl_log_status,
-	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
-	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
-};
-
-static struct video_device solo_v4l2_template = {
-	.name			= SOLO6X10_NAME,
-	.fops			= &solo_v4l2_fops,
-	.ioctl_ops		= &solo_v4l2_ioctl_ops,
-	.minor			= -1,
-	.release		= video_device_release,
-	.tvnorms		= V4L2_STD_NTSC_M | V4L2_STD_PAL,
-};
-
-static const struct v4l2_ctrl_ops solo_ctrl_ops = {
-	.s_ctrl = solo_s_ctrl,
-};
-
-static const struct v4l2_ctrl_config solo_motion_trace_ctrl = {
-	.ops = &solo_ctrl_ops,
-	.id = V4L2_CID_MOTION_TRACE,
-	.name = "Motion Detection Trace",
-	.type = V4L2_CTRL_TYPE_BOOLEAN,
-	.max = 1,
-	.step = 1,
-};
-
-int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
-{
-	int ret;
-	int i;
-
-	init_waitqueue_head(&solo_dev->disp_thread_wait);
-	spin_lock_init(&solo_dev->slock);
-	mutex_init(&solo_dev->lock);
-	INIT_LIST_HEAD(&solo_dev->vidq_active);
-
-	solo_dev->vfd = video_device_alloc();
-	if (!solo_dev->vfd)
-		return -ENOMEM;
-
-	*solo_dev->vfd = solo_v4l2_template;
-	solo_dev->vfd->v4l2_dev = &solo_dev->v4l2_dev;
-	solo_dev->vfd->queue = &solo_dev->vidq;
-	solo_dev->vfd->lock = &solo_dev->lock;
-	v4l2_ctrl_handler_init(&solo_dev->disp_hdl, 1);
-	v4l2_ctrl_new_custom(&solo_dev->disp_hdl, &solo_motion_trace_ctrl, NULL);
-	if (solo_dev->disp_hdl.error) {
-		ret = solo_dev->disp_hdl.error;
-		goto fail;
-	}
-	solo_dev->vfd->ctrl_handler = &solo_dev->disp_hdl;
-
-	video_set_drvdata(solo_dev->vfd, solo_dev);
-
-	solo_dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	solo_dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
-	solo_dev->vidq.ops = &solo_video_qops;
-	solo_dev->vidq.mem_ops = &vb2_dma_contig_memops;
-	solo_dev->vidq.drv_priv = solo_dev;
-	solo_dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
-	solo_dev->vidq.gfp_flags = __GFP_DMA32;
-	solo_dev->vidq.buf_struct_size = sizeof(struct solo_vb2_buf);
-	solo_dev->vidq.lock = &solo_dev->lock;
-	ret = vb2_queue_init(&solo_dev->vidq);
-	if (ret < 0)
-		goto fail;
-
-	solo_dev->alloc_ctx = vb2_dma_contig_init_ctx(&solo_dev->pdev->dev);
-	if (IS_ERR(solo_dev->alloc_ctx)) {
-		dev_err(&solo_dev->pdev->dev, "Can't allocate buffer context");
-		return PTR_ERR(solo_dev->alloc_ctx);
-	}
-
-	/* Cycle all the channels and clear */
-	for (i = 0; i < solo_dev->nr_chans; i++) {
-		solo_v4l2_set_ch(solo_dev, i);
-		while (erase_off(solo_dev))
-			/* Do nothing */;
-	}
-
-	/* Set the default display channel */
-	solo_v4l2_set_ch(solo_dev, 0);
-	while (erase_off(solo_dev))
-		/* Do nothing */;
-
-	ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr);
-	if (ret < 0)
-		goto fail;
-
-	snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
-		 SOLO6X10_NAME, solo_dev->vfd->num);
-
-	dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with "
-		 "%d inputs (%d extended)\n", solo_dev->vfd->num,
-		 solo_dev->nr_chans, solo_dev->nr_ext);
-
-	return 0;
-
-fail:
-	video_device_release(solo_dev->vfd);
-	vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx);
-	v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
-	solo_dev->vfd = NULL;
-	return ret;
-}
-
-void solo_v4l2_exit(struct solo_dev *solo_dev)
-{
-	if (solo_dev->vfd == NULL)
-		return;
-
-	video_unregister_device(solo_dev->vfd);
-	vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx);
-	v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
-	solo_dev->vfd = NULL;
-}
diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h
deleted file mode 100644
index c6154b00fcbd9..0000000000000
--- a/drivers/staging/media/solo6x10/solo6x10.h
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
- *
- * Original author:
- * Ben Collins <bcollins@ubuntu.com>
- *
- * Additional work by:
- * John Brooks <john.brooks@bluecherry.net>
- *
- * 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.
- */
-
-#ifndef __SOLO6X10_H
-#define __SOLO6X10_H
-
-#include <linux/pci.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <linux/list.h>
-#include <linux/wait.h>
-#include <linux/stringify.h>
-#include <linux/io.h>
-#include <linux/atomic.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-
-#include <media/v4l2-dev.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ctrls.h>
-#include <media/videobuf2-core.h>
-
-#include "solo6x10-regs.h"
-
-#ifndef PCI_VENDOR_ID_SOFTLOGIC
-#define PCI_VENDOR_ID_SOFTLOGIC		0x9413
-#define PCI_DEVICE_ID_SOLO6010		0x6010
-#define PCI_DEVICE_ID_SOLO6110		0x6110
-#endif
-
-#ifndef PCI_VENDOR_ID_BLUECHERRY
-#define PCI_VENDOR_ID_BLUECHERRY	0x1BB3
-/* Neugent Softlogic 6010 based cards */
-#define PCI_DEVICE_ID_NEUSOLO_4		0x4304
-#define PCI_DEVICE_ID_NEUSOLO_9		0x4309
-#define PCI_DEVICE_ID_NEUSOLO_16	0x4310
-/* Bluecherry Softlogic 6010 based cards */
-#define PCI_DEVICE_ID_BC_SOLO_4		0x4E04
-#define PCI_DEVICE_ID_BC_SOLO_9		0x4E09
-#define PCI_DEVICE_ID_BC_SOLO_16	0x4E10
-/* Bluecherry Softlogic 6110 based cards */
-#define PCI_DEVICE_ID_BC_6110_4		0x5304
-#define PCI_DEVICE_ID_BC_6110_8		0x5308
-#define PCI_DEVICE_ID_BC_6110_16	0x5310
-#endif /* Bluecherry */
-
-/* Used in pci_device_id, and solo_dev->type */
-#define SOLO_DEV_6010			0
-#define SOLO_DEV_6110			1
-
-#define SOLO6X10_NAME			"solo6x10"
-
-#define SOLO_MAX_CHANNELS		16
-
-#define SOLO6X10_VERSION		"3.0.0"
-
-/*
- * The SOLO6x10 actually has 8 i2c channels, but we only use 2.
- * 0 - Techwell chip(s)
- * 1 - SAA7128
- */
-#define SOLO_I2C_ADAPTERS		2
-#define SOLO_I2C_TW			0
-#define SOLO_I2C_SAA			1
-
-/* DMA Engine setup */
-#define SOLO_NR_P2M			4
-#define SOLO_NR_P2M_DESC		256
-#define SOLO_P2M_DESC_SIZE		(SOLO_NR_P2M_DESC * 16)
-
-/* Encoder standard modes */
-#define SOLO_ENC_MODE_CIF		2
-#define SOLO_ENC_MODE_HD1		1
-#define SOLO_ENC_MODE_D1		9
-
-#define SOLO_DEFAULT_QP			3
-
-#define SOLO_CID_CUSTOM_BASE		(V4L2_CID_USER_BASE | 0xf000)
-#define V4L2_CID_MOTION_TRACE		(SOLO_CID_CUSTOM_BASE+2)
-#define V4L2_CID_OSD_TEXT		(SOLO_CID_CUSTOM_BASE+3)
-
-/*
- * Motion thresholds are in a table of 64x64 samples, with
- * each sample representing 16x16 pixels of the source. In
- * effect, 44x30 samples are used for NTSC, and 44x36 for PAL.
- * The 5th sample on the 10th row is (10*64)+5 = 645.
- *
- * Internally it is stored as a 45x45 array (45*16 = 720, which is the
- * maximum PAL/NTSC width).
- */
-#define SOLO_MOTION_SZ (45)
-
-enum SOLO_I2C_STATE {
-	IIC_STATE_IDLE,
-	IIC_STATE_START,
-	IIC_STATE_READ,
-	IIC_STATE_WRITE,
-	IIC_STATE_STOP
-};
-
-/* Defined in Table 4-16, Page 68-69 of the 6010 Datasheet */
-struct solo_p2m_desc {
-	u32	ctrl;
-	u32	cfg;
-	u32	dma_addr;
-	u32	ext_addr;
-};
-
-struct solo_p2m_dev {
-	struct mutex		mutex;
-	struct completion	completion;
-	int			desc_count;
-	int			desc_idx;
-	struct solo_p2m_desc	*descs;
-	int			error;
-};
-
-#define OSD_TEXT_MAX		44
-
-struct solo_vb2_buf {
-	struct vb2_buffer vb;
-	struct list_head list;
-};
-
-enum solo_enc_types {
-	SOLO_ENC_TYPE_STD,
-	SOLO_ENC_TYPE_EXT,
-};
-
-struct solo_enc_dev {
-	struct solo_dev	*solo_dev;
-	/* V4L2 Items */
-	struct v4l2_ctrl_handler hdl;
-	struct v4l2_ctrl *md_thresholds;
-	struct video_device	*vfd;
-	/* General accounting */
-	struct mutex		lock;
-	spinlock_t		motion_lock;
-	u8			ch;
-	u8			mode, gop, qp, interlaced, interval;
-	u8			bw_weight;
-	u16			motion_thresh;
-	bool			motion_global;
-	bool			motion_enabled;
-	bool			motion_last_state;
-	u8			frames_since_last_motion;
-	u16			width;
-	u16			height;
-
-	/* OSD buffers */
-	char			osd_text[OSD_TEXT_MAX + 1];
-	u8			osd_buf[SOLO_EOSD_EXT_SIZE_MAX]
-					__aligned(4);
-
-	/* VOP stuff */
-	unsigned char		vop[64];
-	int			vop_len;
-	unsigned char		jpeg_header[1024];
-	int			jpeg_len;
-
-	u32			fmt;
-	enum solo_enc_types	type;
-	u32			sequence;
-	struct vb2_queue	vidq;
-	struct list_head	vidq_active;
-	int			desc_count;
-	int			desc_nelts;
-	struct solo_p2m_desc	*desc_items;
-	dma_addr_t		desc_dma;
-	spinlock_t		av_lock;
-};
-
-/* The SOLO6x10 PCI Device */
-struct solo_dev {
-	/* General stuff */
-	struct pci_dev		*pdev;
-	int			type;
-	unsigned int		time_sync;
-	unsigned int		usec_lsb;
-	unsigned int		clock_mhz;
-	u8 __iomem		*reg_base;
-	int			nr_chans;
-	int			nr_ext;
-	u32			irq_mask;
-	u32			motion_mask;
-	spinlock_t		reg_io_lock;
-	struct v4l2_device	v4l2_dev;
-
-	/* tw28xx accounting */
-	u8			tw2865, tw2864, tw2815;
-	u8			tw28_cnt;
-
-	/* i2c related items */
-	struct i2c_adapter	i2c_adap[SOLO_I2C_ADAPTERS];
-	enum SOLO_I2C_STATE	i2c_state;
-	struct mutex		i2c_mutex;
-	int			i2c_id;
-	wait_queue_head_t	i2c_wait;
-	struct i2c_msg		*i2c_msg;
-	unsigned int		i2c_msg_num;
-	unsigned int		i2c_msg_ptr;
-
-	/* P2M DMA Engine */
-	struct solo_p2m_dev	p2m_dev[SOLO_NR_P2M];
-	atomic_t		p2m_count;
-	int			p2m_jiffies;
-	unsigned int		p2m_timeouts;
-
-	/* V4L2 Display items */
-	struct video_device	*vfd;
-	unsigned int		erasing;
-	unsigned int		frame_blank;
-	u8			cur_disp_ch;
-	wait_queue_head_t	disp_thread_wait;
-	struct v4l2_ctrl_handler disp_hdl;
-
-	/* V4L2 Encoder items */
-	struct solo_enc_dev	*v4l2_enc[SOLO_MAX_CHANNELS];
-	u16			enc_bw_remain;
-	/* IDX into hw mp4 encoder */
-	u8			enc_idx;
-
-	/* Current video settings */
-	u32			video_type;
-	u16			video_hsize, video_vsize;
-	u16			vout_hstart, vout_vstart;
-	u16			vin_hstart, vin_vstart;
-	u8			fps;
-
-	/* JPEG Qp setting */
-	spinlock_t      jpeg_qp_lock;
-	u32		jpeg_qp[2];
-
-	/* Audio components */
-	struct snd_card		*snd_card;
-	struct snd_pcm		*snd_pcm;
-	atomic_t		snd_users;
-	int			g723_hw_idx;
-
-	/* sysfs stuffs */
-	struct device		dev;
-	int			sdram_size;
-	struct bin_attribute	sdram_attr;
-	unsigned int		sys_config;
-
-	/* Ring thread */
-	struct task_struct	*ring_thread;
-	wait_queue_head_t	ring_thread_wait;
-
-	/* VOP_HEADER handling */
-	void                    *vh_buf;
-	dma_addr_t		vh_dma;
-	int			vh_size;
-
-	/* Buffer handling */
-	struct vb2_queue	vidq;
-	struct vb2_alloc_ctx	*alloc_ctx;
-	u32			sequence;
-	struct task_struct      *kthread;
-	struct mutex		lock;
-	spinlock_t		slock;
-	int			old_write;
-	struct list_head	vidq_active;
-};
-
-static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg)
-{
-	unsigned long flags;
-	u32 ret;
-	u16 val;
-
-	spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
-
-	ret = readl(solo_dev->reg_base + reg);
-	rmb();
-	pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
-	rmb();
-
-	spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
-
-	return ret;
-}
-
-static inline void solo_reg_write(struct solo_dev *solo_dev, int reg,
-				  u32 data)
-{
-	unsigned long flags;
-	u16 val;
-
-	spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
-
-	writel(data, solo_dev->reg_base + reg);
-	wmb();
-	pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
-	rmb();
-
-	spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
-}
-
-static inline void solo_irq_on(struct solo_dev *dev, u32 mask)
-{
-	dev->irq_mask |= mask;
-	solo_reg_write(dev, SOLO_IRQ_MASK, dev->irq_mask);
-}
-
-static inline void solo_irq_off(struct solo_dev *dev, u32 mask)
-{
-	dev->irq_mask &= ~mask;
-	solo_reg_write(dev, SOLO_IRQ_MASK, dev->irq_mask);
-}
-
-/* Init/exit routines for subsystems */
-int solo_disp_init(struct solo_dev *solo_dev);
-void solo_disp_exit(struct solo_dev *solo_dev);
-
-int solo_gpio_init(struct solo_dev *solo_dev);
-void solo_gpio_exit(struct solo_dev *solo_dev);
-
-int solo_i2c_init(struct solo_dev *solo_dev);
-void solo_i2c_exit(struct solo_dev *solo_dev);
-
-int solo_p2m_init(struct solo_dev *solo_dev);
-void solo_p2m_exit(struct solo_dev *solo_dev);
-
-int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr);
-void solo_v4l2_exit(struct solo_dev *solo_dev);
-
-int solo_enc_init(struct solo_dev *solo_dev);
-void solo_enc_exit(struct solo_dev *solo_dev);
-
-int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr);
-void solo_enc_v4l2_exit(struct solo_dev *solo_dev);
-
-int solo_g723_init(struct solo_dev *solo_dev);
-void solo_g723_exit(struct solo_dev *solo_dev);
-
-/* ISR's */
-int solo_i2c_isr(struct solo_dev *solo_dev);
-void solo_p2m_isr(struct solo_dev *solo_dev, int id);
-void solo_p2m_error_isr(struct solo_dev *solo_dev);
-void solo_enc_v4l2_isr(struct solo_dev *solo_dev);
-void solo_g723_isr(struct solo_dev *solo_dev);
-void solo_motion_isr(struct solo_dev *solo_dev);
-void solo_video_in_isr(struct solo_dev *solo_dev);
-
-/* i2c read/write */
-u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off);
-void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off,
-			u8 data);
-
-/* P2M DMA */
-int solo_p2m_dma_t(struct solo_dev *solo_dev, int wr,
-		   dma_addr_t dma_addr, u32 ext_addr, u32 size,
-		   int repeat, u32 ext_size);
-int solo_p2m_dma(struct solo_dev *solo_dev, int wr,
-		 void *sys_addr, u32 ext_addr, u32 size,
-		 int repeat, u32 ext_size);
-void solo_p2m_fill_desc(struct solo_p2m_desc *desc, int wr,
-			dma_addr_t dma_addr, u32 ext_addr, u32 size,
-			int repeat, u32 ext_size);
-int solo_p2m_dma_desc(struct solo_dev *solo_dev,
-		      struct solo_p2m_desc *desc, dma_addr_t desc_dma,
-		      int desc_cnt);
-
-/* Global s_std ioctl */
-int solo_set_video_type(struct solo_dev *solo_dev, bool is_50hz);
-void solo_update_mode(struct solo_enc_dev *solo_enc);
-
-/* Set the threshold for motion detection */
-int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val);
-int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
-		const u16 *thresholds);
-#define SOLO_DEF_MOT_THRESH		0x0300
-
-/* Write text on OSD */
-int solo_osd_print(struct solo_enc_dev *solo_enc);
-
-/* EEPROM commands */
-unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en);
-unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc);
-int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
-		      unsigned short data);
-
-/* JPEG Qp functions */
-void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch,
-		    unsigned int qp);
-int solo_g_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch);
-
-#define CHK_FLAGS(v, flags) (((v) & (flags)) == (flags))
-
-#endif /* __SOLO6X10_H */